plasma/kernel/filesys.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma File System |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 4/26/07 |
| 5 | * FILENAME: filesys.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma File System. Supports RAM, flash, and disk file systems. |
| 11 | * Possible call tree: |
| 12 | * OS_fclose() |
| 13 | * FileFindRecursive() //find the existing file |
| 14 | * FileOpen() //open root file system |
| 15 | * FileFind() //find the next level of directory |
| 16 | * OS_fread() //read the directory file |
| 17 | * BlockRead() //read blocks of directory |
| 18 | * MediaBlockRead() //low level read |
| 19 | * FileOpen() //open next directory |
| 20 | * OS_fwrite() //write file entry into directory |
| 21 | * BlockRead() //flush changes to directory |
| 22 | *--------------------------------------------------------------------*/ |
| 23 | #ifdef WIN32 |
| 24 | #include <stdio.h> |
| 25 | #include <stdlib.h> |
| 26 | #include <string.h> |
| 27 | #define _LIBC |
| 28 | #endif |
| 29 | #include "rtos.h" |
| 30 | |
| 31 | #define FLASH_SIZE 1024*1024*16 |
| 32 | #define FLASH_SECTOR_SIZE 1024*128 |
| 33 | #define FLASH_BLOCK_SIZE 512 |
| 34 | #define FLASH_LN2_SIZE 9 //2^FLASH_LN2_SIZE == FLASH_BLOCK_SIZE |
| 35 | #define FLASH_OFFSET FLASH_SECTOR_SIZE //offset to start of flash file system |
| 36 | |
| 37 | #define BLOCK_SIZE 512 |
| 38 | #define FILE_NAME_SIZE 40 |
| 39 | #define FULL_NAME_SIZE 128 |
| 40 | #define BLOCK_MALLOC 0x0 |
| 41 | #define BLOCK_EOF 0xffffffff |
| 42 | |
| 43 | typedef enum { |
| 44 | FILE_MEDIA_RAM, |
| 45 | FILE_MEDIA_FLASH, |
| 46 | FILE_MEDIA_DISK |
| 47 | } OS_MediaType_e; |
| 48 | |
| 49 | typedef struct OS_FileEntry_s { |
| 50 | char name[FILE_NAME_SIZE]; |
| 51 | uint32 blockIndex; //first block of file |
| 52 | uint32 modifiedTime; |
| 53 | uint32 length; |
| 54 | uint8 isDirectory; |
| 55 | uint8 attributes; |
| 56 | uint8 valid; |
| 57 | uint8 mediaType; |
| 58 | uint16 blockSize; //Normally BLOCK_SIZE |
| 59 | } OS_FileEntry_t; |
| 60 | |
| 61 | typedef struct OS_Block_s { |
| 62 | uint32 next; |
| 63 | uint8 data[4]; |
| 64 | } OS_Block_t; |
| 65 | |
| 66 | struct OS_FILE_s { |
| 67 | OS_FileEntry_t fileEntry; //written to directory upon OS_fclose() |
| 68 | uint8 fileModified; |
| 69 | uint8 blockModified; |
| 70 | uint32 blockIndex; //index of block |
| 71 | uint32 blockOffset; //byte offset into block |
| 72 | uint32 fileOffset; //byte offset into file |
| 73 | char fullname[FULL_NAME_SIZE]; //includes full path |
| 74 | OS_Block_t *block; |
| 75 | OS_Block_t *blockLocal; //local copy for flash or disk file system |
| 76 | }; |
| 77 | |
| 78 | static OS_FileEntry_t rootFileEntry; |
| 79 | static OS_Mutex_t *mutexFilesys; |
| 80 | |
| 81 | // Public prototypes |
| 82 | #ifndef _FILESYS_ |
| 83 | typedef struct OS_FILE_s OS_FILE; |
| 84 | #endif |
| 85 | OS_FILE *OS_fopen(char *name, char *mode); |
| 86 | void OS_fclose(OS_FILE *file); |
| 87 | int OS_fread(void *buffer, int size, int count, OS_FILE *file); |
| 88 | int OS_fwrite(void *buffer, int size, int count, OS_FILE *file); |
| 89 | int OS_fseek(OS_FILE *file, int offset, int mode); |
| 90 | int OS_fmkdir(char *name); |
| 91 | int OS_fdir(OS_FILE *dir, char name[64]); |
| 92 | void OS_fdelete(char *name); |
| 93 | |
| 94 | |
| 95 | /***************** Media Functions Start ***********************/ |
| 96 | #ifdef INCLUDE_FLASH |
| 97 | #define FLASH_BLOCKS FLASH_SIZE/FLASH_BLOCK_SIZE |
| 98 | #define FLASH_START (FLASH_OFFSET+FLASH_BLOCKS/8*2)/FLASH_BLOCK_SIZE |
| 99 | static unsigned char FlashBlockEmpty[FLASH_BLOCKS/8]; |
| 100 | static unsigned char FlashBlockUsed[FLASH_BLOCKS/8]; |
| 101 | static int FlashBlock; |
| 102 | |
| 103 | //Free unused flash blocks |
| 104 | static int MediaBlockCleanup(void) |
| 105 | { |
| 106 | int i, sector, block, count=0; |
| 107 | unsigned char *buf; |
| 108 | |
| 109 | printf("FlashCleanup\n"); |
| 110 | buf = (unsigned char*)malloc(FLASH_SECTOR_SIZE); |
| 111 | if(buf == NULL) |
| 112 | return 0; |
| 113 | for(sector = FLASH_OFFSET / FLASH_SECTOR_SIZE; sector < FLASH_SIZE / FLASH_SECTOR_SIZE; ++sector) |
| 114 | { |
| 115 | FlashRead((uint16*)buf, FLASH_SECTOR_SIZE*sector, FLASH_SECTOR_SIZE); |
| 116 | if(sector == FLASH_OFFSET / FLASH_SECTOR_SIZE) |
| 117 | { |
| 118 | for(i = 0; i < FLASH_BLOCKS/8; ++i) |
| 119 | FlashBlockEmpty[i] |= ~FlashBlockUsed[i]; |
| 120 | memcpy(buf, FlashBlockEmpty, sizeof(FlashBlockEmpty)); |
| 121 | memset(FlashBlockUsed, 0xff, sizeof(FlashBlockUsed)); |
| 122 | memset(buf+sizeof(FlashBlockEmpty), 0xff, sizeof(FlashBlockUsed)); |
| 123 | } |
| 124 | //Erase empty blocks |
| 125 | for(block = 0; block < FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE; ++block) |
| 126 | { |
| 127 | i = sector * FLASH_SECTOR_SIZE / FLASH_BLOCK_SIZE + block; |
| 128 | if(i < FLASH_BLOCKS/8 && (FlashBlockEmpty[i >> 3] & (1 << (i & 7)))) |
| 129 | { |
| 130 | memset(buf + FLASH_BLOCK_SIZE*block, 0xff, FLASH_BLOCK_SIZE); |
| 131 | ++count; |
| 132 | } |
| 133 | } |
| 134 | FlashErase(FLASH_SECTOR_SIZE * sector); |
| 135 | FlashWrite((uint16*)buf, FLASH_SECTOR_SIZE * sector, FLASH_SECTOR_SIZE); |
| 136 | } |
| 137 | free(buf); |
| 138 | return count; |
| 139 | } |
| 140 | |
| 141 | |
| 142 | int MediaBlockInit(void) |
| 143 | { |
| 144 | FlashRead((uint16*)FlashBlockEmpty, FLASH_OFFSET, sizeof(FlashBlockEmpty)); |
| 145 | FlashRead((uint16*)FlashBlockUsed, FLASH_OFFSET+sizeof(FlashBlockEmpty), |
| 146 | sizeof(FlashBlockUsed)); |
| 147 | FlashBlock = FLASH_START; |
| 148 | return FlashBlockEmpty[FlashBlock >> 3] & (1 << (FlashBlock & 7)); |
| 149 | } |
| 150 | #endif |
| 151 | |
| 152 | |
| 153 | static uint32 MediaBlockMalloc(OS_FILE *file) |
| 154 | { |
| 155 | int i, j; |
| 156 | (void)i; (void)j; |
| 157 | |
| 158 | if(file->fileEntry.mediaType == FILE_MEDIA_RAM) |
| 159 | return (uint32)malloc(file->fileEntry.blockSize); |
| 160 | #ifdef INCLUDE_FLASH |
| 161 | //Find empty flash block |
| 162 | for(i = FlashBlock; i < FLASH_BLOCKS; ++i) |
| 163 | { |
| 164 | if(FlashBlockEmpty[i >> 3] & (1 << (i & 7))) |
| 165 | { |
| 166 | FlashBlock = i + 1; |
| 167 | FlashBlockEmpty[i >> 3] &= ~(1 << (i & 7)); |
| 168 | j = i >> 3; |
| 169 | j &= ~1; |
| 170 | FlashWrite((uint16*)(FlashBlockEmpty + j), FLASH_OFFSET + j, 2); |
| 171 | return i; |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | i = MediaBlockCleanup(); |
| 176 | if(i == 0) |
| 177 | return 0; |
| 178 | FlashBlock = FLASH_START; |
| 179 | return MediaBlockMalloc(file); |
| 180 | #else |
| 181 | return 0; |
| 182 | #endif |
| 183 | } |
| 184 | |
| 185 | |
| 186 | static void MediaBlockFree(OS_FILE *file, uint32 blockIndex) |
| 187 | { |
| 188 | if(file->fileEntry.mediaType == FILE_MEDIA_RAM) |
| 189 | free((void*)blockIndex); |
| 190 | #ifdef INCLUDE_FLASH |
| 191 | else |
| 192 | { |
| 193 | int i=blockIndex, j; |
| 194 | FlashBlockUsed[i >> 3] &= ~(1 << (i & 7)); |
| 195 | j = i >> 3; |
| 196 | j &= ~1; |
| 197 | FlashWrite((uint16*)(FlashBlockUsed + j), FLASH_OFFSET + sizeof(FlashBlockEmpty) + j, 2); |
| 198 | } |
| 199 | #endif |
| 200 | } |
| 201 | |
| 202 | |
| 203 | static void MediaBlockRead(OS_FILE *file, uint32 blockIndex) |
| 204 | { |
| 205 | if(file->fileEntry.mediaType == FILE_MEDIA_RAM) |
| 206 | file->block = (OS_Block_t*)blockIndex; |
| 207 | #ifdef INCLUDE_FLASH |
| 208 | else |
| 209 | { |
| 210 | if(file->blockLocal == NULL) |
| 211 | file->blockLocal = (OS_Block_t*)malloc(FLASH_BLOCK_SIZE); |
| 212 | file->block = file->blockLocal; |
| 213 | FlashRead((uint16*)file->block, blockIndex << FLASH_LN2_SIZE, FLASH_BLOCK_SIZE); |
| 214 | } |
| 215 | #endif |
| 216 | } |
| 217 | |
| 218 | |
| 219 | static void MediaBlockWrite(OS_FILE *file, uint32 blockIndex) |
| 220 | { |
| 221 | (void)file; |
| 222 | (void)blockIndex; |
| 223 | #ifdef INCLUDE_FLASH |
| 224 | if(file->fileEntry.mediaType != FILE_MEDIA_RAM) |
| 225 | FlashWrite((uint16*)file->block, blockIndex << FLASH_LN2_SIZE, FLASH_BLOCK_SIZE); |
| 226 | #endif |
| 227 | } |
| 228 | |
| 229 | /***************** Media Functions End *************************/ |
| 230 | |
| 231 | // Get the next block and write the old block if it was modified |
| 232 | static void BlockRead(OS_FILE *file, uint32 blockIndex) |
| 233 | { |
| 234 | uint32 blockIndexSave = blockIndex; |
| 235 | |
| 236 | OS_MutexPend(mutexFilesys); |
| 237 | if(blockIndex == BLOCK_MALLOC) |
| 238 | { |
| 239 | // Get a new block |
| 240 | blockIndex = MediaBlockMalloc(file); |
| 241 | if(blockIndex == 0) |
| 242 | blockIndex = BLOCK_EOF; |
| 243 | if(file->block) |
| 244 | { |
| 245 | // Set next pointer in previous block |
| 246 | file->block->next = blockIndex; |
| 247 | file->blockModified = 1; |
| 248 | } |
| 249 | } |
| 250 | if(file->block && file->blockModified) |
| 251 | { |
| 252 | // Write block back to flash or disk |
| 253 | MediaBlockWrite(file, file->blockIndex); |
| 254 | file->blockModified = 0; |
| 255 | } |
| 256 | if(blockIndex == BLOCK_EOF) |
| 257 | { |
| 258 | OS_MutexPost(mutexFilesys); |
| 259 | return; |
| 260 | } |
| 261 | file->blockIndex = blockIndex; |
| 262 | file->blockOffset = 0; |
| 263 | MediaBlockRead(file, blockIndex); |
| 264 | if(blockIndexSave == BLOCK_MALLOC) |
| 265 | { |
| 266 | memset(file->block, 0xff, file->fileEntry.blockSize); |
| 267 | file->blockModified = 1; |
| 268 | } |
| 269 | OS_MutexPost(mutexFilesys); |
| 270 | } |
| 271 | |
| 272 | |
| 273 | int OS_fread(void *buffer, int size, int count, OS_FILE *file) |
| 274 | { |
| 275 | int items, bytes; |
| 276 | uint8 *buf = (uint8*)buffer; |
| 277 | |
| 278 | for(items = 0; items < count; ++items) |
| 279 | { |
| 280 | for(bytes = 0; bytes < size; ++bytes) |
| 281 | { |
| 282 | if(file->fileOffset >= file->fileEntry.length && |
| 283 | file->fileEntry.isDirectory == 0) |
| 284 | return items; |
| 285 | if(file->blockOffset >= file->fileEntry.blockSize - sizeof(uint32)) |
| 286 | { |
| 287 | if(file->block->next == BLOCK_EOF) |
| 288 | return items; |
| 289 | BlockRead(file, file->block->next); |
| 290 | } |
| 291 | *buf++ = file->block->data[file->blockOffset++]; |
| 292 | ++file->fileOffset; |
| 293 | } |
| 294 | } |
| 295 | return items; |
| 296 | } |
| 297 | |
| 298 | |
| 299 | int OS_fwrite(void *buffer, int size, int count, OS_FILE *file) |
| 300 | { |
| 301 | int items, bytes; |
| 302 | uint8 *buf = (uint8*)buffer; |
| 303 | |
| 304 | OS_MutexPend(mutexFilesys); |
| 305 | file->blockModified = 1; |
| 306 | for(items = 0; items < count; ++items) |
| 307 | { |
| 308 | for(bytes = 0; bytes < size; ++bytes) |
| 309 | { |
| 310 | if(file->blockOffset >= file->fileEntry.blockSize - sizeof(uint32)) |
| 311 | { |
| 312 | if(file->block->next == BLOCK_EOF) |
| 313 | file->block->next = BLOCK_MALLOC; |
| 314 | BlockRead(file, file->block->next); |
| 315 | if(file->blockIndex == BLOCK_EOF) |
| 316 | { |
| 317 | count = 0; |
| 318 | --items; |
| 319 | break; |
| 320 | } |
| 321 | file->blockModified = 1; |
| 322 | } |
| 323 | file->block->data[file->blockOffset++] = *buf++; |
| 324 | ++file->fileOffset; |
| 325 | } |
| 326 | } |
| 327 | file->blockModified = 1; |
| 328 | file->fileModified = 1; |
| 329 | if(file->fileOffset > file->fileEntry.length) |
| 330 | file->fileEntry.length = file->fileOffset; |
| 331 | OS_MutexPost(mutexFilesys); |
| 332 | return items; |
| 333 | } |
| 334 | |
| 335 | |
| 336 | int OS_fseek(OS_FILE *file, int offset, int mode) |
| 337 | { |
| 338 | if(mode == 1) //SEEK_CUR |
| 339 | offset += file->fileOffset; |
| 340 | else if(mode == 2) //SEEK_END |
| 341 | offset += file->fileEntry.length; |
| 342 | file->fileOffset = offset; |
| 343 | BlockRead(file, file->fileEntry.blockIndex); |
| 344 | while(offset > (int)file->fileEntry.blockSize - (int)sizeof(uint32)) |
| 345 | { |
| 346 | BlockRead(file, file->block->next); |
| 347 | offset -= file->fileEntry.blockSize - (int)sizeof(uint32); |
| 348 | } |
| 349 | file->blockOffset = offset; |
| 350 | return 0; |
| 351 | } |
| 352 | |
| 353 | |
| 354 | static int FileOpen(OS_FILE *file, char *name, OS_FileEntry_t *fileEntry) |
| 355 | { |
| 356 | memset(file, 0, sizeof(OS_FILE)); |
| 357 | if(fileEntry == NULL) |
| 358 | { |
| 359 | // Open root file |
| 360 | memcpy(&file->fileEntry, &rootFileEntry, sizeof(OS_FileEntry_t)); |
| 361 | } |
| 362 | else if(fileEntry->valid == 1) |
| 363 | { |
| 364 | // Open existing file |
| 365 | memcpy(&file->fileEntry, fileEntry, sizeof(OS_FileEntry_t)); |
| 366 | } |
| 367 | else |
| 368 | { |
| 369 | // Initialize new file |
| 370 | file->fileModified = 1; |
| 371 | file->blockModified = 1; |
| 372 | memset(&file->fileEntry, 0, sizeof(OS_FileEntry_t)); |
| 373 | file->fileEntry.isDirectory = 0; |
| 374 | file->fileEntry.length = 0; |
| 375 | strncpy(file->fileEntry.name, name, FILE_NAME_SIZE-1); |
| 376 | file->fileEntry.blockIndex = 0; |
| 377 | file->fileEntry.valid = 1; |
| 378 | file->fileEntry.blockSize = fileEntry->blockSize; |
| 379 | file->fileEntry.mediaType = fileEntry->mediaType; |
| 380 | } |
| 381 | BlockRead(file, file->fileEntry.blockIndex); //Get first block |
| 382 | file->fileEntry.blockIndex = file->blockIndex; |
| 383 | file->fileOffset = 0; |
| 384 | if(file->blockIndex == BLOCK_EOF) |
| 385 | return -1; |
| 386 | return 0; |
| 387 | } |
| 388 | |
| 389 | |
| 390 | static int FileFind(OS_FILE *directory, char *name, OS_FileEntry_t *fileEntry) |
| 391 | { |
| 392 | int count, rc = -1; |
| 393 | uint32 blockIndex, blockOffset; |
| 394 | uint32 blockIndexEmpty=BLOCK_EOF, blockOffsetEmpty=0; |
| 395 | |
| 396 | // Loop through files in directory |
| 397 | for(;;) |
| 398 | { |
| 399 | blockIndex = directory->blockIndex; |
| 400 | blockOffset = directory->blockOffset; |
| 401 | count = OS_fread(fileEntry, sizeof(OS_FileEntry_t), 1, directory); |
| 402 | if(count == 0 || fileEntry->blockIndex == BLOCK_EOF) |
| 403 | break; |
| 404 | if(fileEntry->valid == 1 && strcmp(fileEntry->name, name) == 0) |
| 405 | { |
| 406 | rc = 0; //Found the file in the directory |
| 407 | break; |
| 408 | } |
| 409 | if(fileEntry->valid != 1 && blockIndexEmpty == BLOCK_EOF) |
| 410 | { |
| 411 | blockIndexEmpty = blockIndex; |
| 412 | blockOffsetEmpty = blockOffset; |
| 413 | } |
| 414 | } |
| 415 | if(rc == 0 || directory->fileEntry.mediaType == FILE_MEDIA_FLASH || |
| 416 | blockIndexEmpty == BLOCK_EOF) |
| 417 | { |
| 418 | // Backup to start of fileEntry or last entry in directory |
| 419 | if(directory->blockIndex != blockIndex) |
| 420 | BlockRead(directory, blockIndex); |
| 421 | directory->blockOffset = blockOffset; |
| 422 | } |
| 423 | else |
| 424 | { |
| 425 | // Backup to empty slot |
| 426 | if(directory->blockIndex != blockIndexEmpty) |
| 427 | BlockRead(directory, blockIndexEmpty); |
| 428 | directory->blockOffset = blockOffsetEmpty; |
| 429 | } |
| 430 | return rc; |
| 431 | } |
| 432 | |
| 433 | |
| 434 | static int FileFindRecursive(OS_FILE *directory, char *name, |
| 435 | OS_FileEntry_t *fileEntry, char *filename) |
| 436 | { |
| 437 | int rc, length; |
| 438 | |
| 439 | rc = FileOpen(directory, NULL, NULL); //Open root directory |
| 440 | for(;;) |
| 441 | { |
| 442 | if(name[0] == '/') |
| 443 | ++name; |
| 444 | for(length = 0; length < FILE_NAME_SIZE; ++length) |
| 445 | { |
| 446 | if(name[length] == 0 || name[length] == '/') |
| 447 | break; |
| 448 | filename[length] = name[length]; |
| 449 | } |
| 450 | filename[length] = 0; |
| 451 | rc = FileFind(directory, filename, fileEntry); //Find file |
| 452 | if(rc) |
| 453 | { |
| 454 | // File not found |
| 455 | fileEntry->mediaType = directory->fileEntry.mediaType; |
| 456 | fileEntry->blockSize = directory->fileEntry.blockSize; |
| 457 | fileEntry->valid = 0; |
| 458 | if(strstr(name, "/") == NULL) |
| 459 | return rc; |
| 460 | else |
| 461 | return -2; //can't find parent directory |
| 462 | } |
| 463 | name += length; |
| 464 | if(name[0]) |
| 465 | rc = FileOpen(directory, filename, fileEntry); //Open subdir |
| 466 | else |
| 467 | break; |
| 468 | } |
| 469 | return rc; |
| 470 | } |
| 471 | |
| 472 | |
| 473 | OS_FILE *OS_fopen(char *name, char *mode) |
| 474 | { |
| 475 | OS_FILE *file; |
| 476 | OS_FileEntry_t fileEntry; |
| 477 | OS_FILE dir; |
| 478 | char filename[FILE_NAME_SIZE]; //Name without directories |
| 479 | int rc; |
| 480 | |
| 481 | if(rootFileEntry.blockIndex == 0) |
| 482 | { |
| 483 | // Mount file system |
| 484 | mutexFilesys = OS_MutexCreate("filesys"); |
| 485 | memset(&dir, 0, sizeof(OS_FILE)); |
| 486 | dir.fileEntry.blockSize = BLOCK_SIZE; |
| 487 | //dir.fileEntry.mediaType = FILE_MEDIA_FLASH; //Test flash |
| 488 | BlockRead(&dir, BLOCK_MALLOC); |
| 489 | strcpy(rootFileEntry.name, "/"); |
| 490 | rootFileEntry.mediaType = dir.fileEntry.mediaType; |
| 491 | rootFileEntry.blockIndex = dir.blockIndex; |
| 492 | rootFileEntry.blockSize = dir.fileEntry.blockSize; |
| 493 | rootFileEntry.isDirectory = 1; |
| 494 | BlockRead(&dir, BLOCK_EOF); //Flush data |
| 495 | #ifdef INCLUDE_FLASH |
| 496 | file = OS_fopen("flash", "w+"); |
| 497 | if(file == NULL) |
| 498 | return NULL; |
| 499 | file->fileEntry.isDirectory = 1; |
| 500 | file->fileEntry.mediaType = FILE_MEDIA_FLASH; |
| 501 | file->fileEntry.blockSize = FLASH_BLOCK_SIZE; |
| 502 | file->blockLocal = file->block; |
| 503 | file->block = NULL; |
| 504 | rc = MediaBlockInit(); |
| 505 | if(rc == 1) |
| 506 | BlockRead(file, BLOCK_MALLOC); |
| 507 | else |
| 508 | BlockRead(file, FLASH_START); |
| 509 | file->fileEntry.blockIndex = file->blockIndex; |
| 510 | OS_fclose(file); |
| 511 | #endif |
| 512 | } |
| 513 | |
| 514 | file = (OS_FILE*)malloc(sizeof(OS_FILE)); |
| 515 | if(file == NULL) |
| 516 | return NULL; |
| 517 | OS_MutexPend(mutexFilesys); |
| 518 | if(name[0] == 0 || strcmp(name, "/") == 0) |
| 519 | { |
| 520 | FileOpen(file, NULL, NULL); |
| 521 | OS_MutexPost(mutexFilesys); |
| 522 | return file; |
| 523 | } |
| 524 | if(mode[0] == 'w') |
| 525 | { |
| 526 | //Don't over write a directory |
| 527 | fileEntry.isDirectory = 0; |
| 528 | rc = FileFindRecursive(&dir, name, &fileEntry, filename); |
| 529 | if(dir.blockLocal) |
| 530 | free(dir.blockLocal); |
| 531 | if(rc == 0) |
| 532 | { |
| 533 | if(fileEntry.isDirectory) |
| 534 | { |
| 535 | free(file); |
| 536 | return NULL; |
| 537 | } |
| 538 | OS_fdelete(name); |
| 539 | } |
| 540 | } |
| 541 | rc = FileFindRecursive(&dir, name, &fileEntry, filename); |
| 542 | if(dir.blockLocal) |
| 543 | free(dir.blockLocal); |
| 544 | if(rc == -2 || (rc && mode[0] == 'r')) |
| 545 | { |
| 546 | free(file); |
| 547 | OS_MutexPost(mutexFilesys); |
| 548 | return NULL; |
| 549 | } |
| 550 | if(rc) |
| 551 | fileEntry.valid = 0; |
| 552 | rc = FileOpen(file, filename, &fileEntry); //Open file |
| 553 | file->fullname[0] = 0; |
| 554 | strncat(file->fullname, name, FULL_NAME_SIZE); |
| 555 | OS_MutexPost(mutexFilesys); |
| 556 | if(mode[0] == 'a') |
| 557 | OS_fseek(file, 0, 2); //goto end of file |
| 558 | return file; |
| 559 | } |
| 560 | |
| 561 | |
| 562 | void OS_fclose(OS_FILE *file) |
| 563 | { |
| 564 | OS_FileEntry_t fileEntry; |
| 565 | OS_FILE dir; |
| 566 | char filename[FILE_NAME_SIZE]; |
| 567 | int rc; |
| 568 | |
| 569 | if(file->fileModified) |
| 570 | { |
| 571 | // Write file->fileEntry into parent directory |
| 572 | OS_MutexPend(mutexFilesys); |
| 573 | BlockRead(file, BLOCK_EOF); |
| 574 | rc = FileFindRecursive(&dir, file->fullname, &fileEntry, filename); |
| 575 | if(file->fileEntry.mediaType == FILE_MEDIA_FLASH && rc == 0) |
| 576 | { |
| 577 | // Invalidate old entry and add new entry at the end |
| 578 | fileEntry.valid = 0; |
| 579 | OS_fwrite(&fileEntry, sizeof(OS_FileEntry_t), 1, &dir); |
| 580 | FileFind(&dir, "endoffile", &fileEntry); |
| 581 | } |
| 582 | OS_fwrite(&file->fileEntry, sizeof(OS_FileEntry_t), 1, &dir); |
| 583 | BlockRead(&dir, BLOCK_EOF); //flush data |
| 584 | if(dir.blockLocal) |
| 585 | free(dir.blockLocal); |
| 586 | OS_MutexPost(mutexFilesys); |
| 587 | } |
| 588 | if(file->blockLocal) |
| 589 | free(file->blockLocal); |
| 590 | free(file); |
| 591 | } |
| 592 | |
| 593 | |
| 594 | int OS_fmkdir(char *name) |
| 595 | { |
| 596 | OS_FILE *file; |
| 597 | file = OS_fopen(name, "w+"); |
| 598 | if(file == NULL) |
| 599 | return -1; |
| 600 | file->fileEntry.isDirectory = 1; |
| 601 | OS_fclose(file); |
| 602 | return 0; |
| 603 | } |
| 604 | |
| 605 | |
| 606 | void OS_fdelete(char *name) |
| 607 | { |
| 608 | OS_FILE dir, file; |
| 609 | OS_FileEntry_t fileEntry; |
| 610 | int rc; |
| 611 | uint32 blockIndex; |
| 612 | char filename[FILE_NAME_SIZE]; //Name without directories |
| 613 | |
| 614 | OS_MutexPend(mutexFilesys); |
| 615 | rc = FileFindRecursive(&dir, name, &fileEntry, filename); |
| 616 | if(rc == 0) |
| 617 | { |
| 618 | FileOpen(&file, NULL, &fileEntry); |
| 619 | for(blockIndex = file.blockIndex; file.block->next != BLOCK_EOF; blockIndex = file.blockIndex) |
| 620 | { |
| 621 | BlockRead(&file, file.block->next); |
| 622 | MediaBlockFree(&file, blockIndex); |
| 623 | } |
| 624 | MediaBlockFree(&file, blockIndex); |
| 625 | fileEntry.valid = 0; |
| 626 | OS_fwrite((char*)&fileEntry, sizeof(OS_FileEntry_t), 1, &dir); |
| 627 | BlockRead(&dir, BLOCK_EOF); |
| 628 | if(file.blockLocal) |
| 629 | free(file.blockLocal); |
| 630 | } |
| 631 | if(dir.blockLocal) |
| 632 | free(dir.blockLocal); |
| 633 | OS_MutexPost(mutexFilesys); |
| 634 | } |
| 635 | |
| 636 | |
| 637 | int OS_flength(char *entry) |
| 638 | { |
| 639 | OS_FileEntry_t *entry2=(OS_FileEntry_t*)entry; |
| 640 | return entry2->length; |
| 641 | } |
| 642 | |
| 643 | |
| 644 | int OS_fdir(OS_FILE *dir, char name[64]) |
| 645 | { |
| 646 | OS_FileEntry_t *fileEntry = (OS_FileEntry_t*)name; |
| 647 | int count; |
| 648 | for(;;) |
| 649 | { |
| 650 | count = OS_fread(fileEntry, sizeof(OS_FileEntry_t), 1, dir); |
| 651 | if(count == 0 || fileEntry->blockIndex == BLOCK_EOF) |
| 652 | return -1; |
| 653 | if(fileEntry->valid == 1) |
| 654 | break; |
| 655 | } |
| 656 | return 0; |
| 657 | } |
| 658 | |
| 659 | /*************************************************/ |
| 660 | #define TEST_FILES |
| 661 | #ifdef TEST_FILES |
| 662 | int DirRecursive(char *name) |
| 663 | { |
| 664 | OS_FileEntry_t fileEntry; |
| 665 | OS_FILE *dir; |
| 666 | char fullname[FULL_NAME_SIZE]; |
| 667 | int rc; |
| 668 | |
| 669 | dir = OS_fopen(name, "r"); |
| 670 | for(;;) |
| 671 | { |
| 672 | rc = OS_fdir(dir, (char*)&fileEntry); |
| 673 | if(rc) |
| 674 | break; |
| 675 | printf("%s %d\n", fileEntry.name, fileEntry.length); |
| 676 | if(fileEntry.isDirectory) |
| 677 | { |
| 678 | if(strcmp(name, "/") == 0) |
| 679 | sprintf(fullname, "/%s", fileEntry.name); |
| 680 | else |
| 681 | sprintf(fullname, "%s/%s", name, fileEntry.name); |
| 682 | DirRecursive(fullname); |
| 683 | } |
| 684 | } |
| 685 | OS_fclose(dir); |
| 686 | return 0; |
| 687 | } |
| 688 | |
| 689 | int OS_ftest(void) |
| 690 | { |
| 691 | OS_FILE *file; |
| 692 | char *buf; |
| 693 | int count; |
| 694 | int i, j; |
| 695 | |
| 696 | buf = (char*)malloc(5000); |
| 697 | memset(buf, 0, 5000); |
| 698 | for(count = 0; count < 4000; ++count) |
| 699 | buf[count] = (char)('A' + (count % 26)); |
| 700 | OS_fmkdir("dir"); |
| 701 | OS_fmkdir("/dir/subdir"); |
| 702 | file = OS_fopen("/dir/subdir/test.txt", "w"); |
| 703 | count = OS_fwrite(buf, 1, 4000, file); |
| 704 | OS_fclose(file); |
| 705 | memset(buf, 0, 5000); |
| 706 | file = OS_fopen("/dir/subdir/test.txt", "r"); |
| 707 | count = OS_fread(buf, 1, 5000, file); |
| 708 | OS_fclose(file); |
| 709 | printf("(%s)\n", buf); |
| 710 | |
| 711 | DirRecursive("/"); |
| 712 | |
| 713 | for(i = 0; i < 5; ++i) |
| 714 | { |
| 715 | sprintf(buf, "/dir%d", i); |
| 716 | OS_fmkdir(buf); |
| 717 | for(j = 0; j < 5; ++j) |
| 718 | { |
| 719 | sprintf(buf, "/dir%d/file%d%d", i, i, j); |
| 720 | file = OS_fopen(buf, "w"); |
| 721 | sprintf(buf, "i=%d j=%d", i, j); |
| 722 | OS_fwrite(buf, 1, 8, file); |
| 723 | OS_fclose(file); |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | OS_fdelete("/dir1/file12"); |
| 728 | DirRecursive("/"); |
| 729 | file = OS_fopen("/baddir/myfile.txt", "w"); |
| 730 | if(file) |
| 731 | printf("ERROR!\n"); |
| 732 | |
| 733 | for(i = 0; i < 5; ++i) |
| 734 | { |
| 735 | for(j = 0; j < 5; ++j) |
| 736 | { |
| 737 | sprintf(buf, "/dir%d/file%d%d", i, i, j); |
| 738 | file = OS_fopen(buf, "r"); |
| 739 | if(file) |
| 740 | { |
| 741 | count = OS_fread(buf, 1, 500, file); |
| 742 | printf("i=%d j=%d count=%d (%s)\n", i, j, count, buf); |
| 743 | OS_fclose(file); |
| 744 | } |
| 745 | } |
| 746 | } |
| 747 | |
| 748 | OS_fdelete("/dir/subdir/test.txt"); |
| 749 | OS_fdelete("/dir/subdir"); |
| 750 | OS_fdelete("/dir"); |
| 751 | for(i = 0; i < 5; ++i) |
| 752 | { |
| 753 | for(j = 0; j < 5; ++j) |
| 754 | { |
| 755 | sprintf(buf, "/dir%d/file%d%d", i, i, j); |
| 756 | OS_fdelete(buf); |
| 757 | } |
| 758 | sprintf(buf, "/dir%d", i); |
| 759 | OS_fdelete(buf); |
| 760 | } |
| 761 | |
| 762 | DirRecursive("/"); |
| 763 | |
| 764 | free(buf); |
| 765 | return 0; |
| 766 | } |
| 767 | #endif //TEST_FILES |
plasma/kernel/libc.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: ANSI C Library |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 12/17/05 |
| 5 | * FILENAME: libc.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Subset of the ANSI C library |
| 11 | *--------------------------------------------------------------------*/ |
| 12 | #define NO_ELLIPSIS |
| 13 | #include "rtos.h" |
| 14 | |
| 15 | |
| 16 | char *strcpy(char *dst, const char *src) |
| 17 | { |
| 18 | char *dstSave=dst; |
| 19 | int c; |
| 20 | do |
| 21 | { |
| 22 | c = *dst++ = *src++; |
| 23 | } while(c); |
| 24 | return dstSave; |
| 25 | } |
| 26 | |
| 27 | |
| 28 | char *strncpy(char *dst, const char *src, int count) |
| 29 | { |
| 30 | int c=1; |
| 31 | char *dstSave=dst; |
| 32 | while(count-- > 0 && c) |
| 33 | c = *dst++ = *src++; |
| 34 | *dst = 0; |
| 35 | return dstSave; |
| 36 | } |
| 37 | |
| 38 | |
| 39 | char *strcat(char *dst, const char *src) |
| 40 | { |
| 41 | int c; |
| 42 | char *dstSave=dst; |
| 43 | while(*dst) |
| 44 | ++dst; |
| 45 | do |
| 46 | { |
| 47 | c = *dst++ = *src++; |
| 48 | } while(c); |
| 49 | return dstSave; |
| 50 | } |
| 51 | |
| 52 | |
| 53 | char *strncat(char *dst, const char *src, int count) |
| 54 | { |
| 55 | int c=1; |
| 56 | char *dstSave=dst; |
| 57 | while(*dst && --count > 0) |
| 58 | ++dst; |
| 59 | while(--count > 0 && c) |
| 60 | c = *dst++ = *src++; |
| 61 | *dst = 0; |
| 62 | return dstSave; |
| 63 | } |
| 64 | |
| 65 | |
| 66 | int strcmp(const char *string1, const char *string2) |
| 67 | { |
| 68 | int diff, c; |
| 69 | for(;;) |
| 70 | { |
| 71 | diff = *string1++ - (c = *string2++); |
| 72 | if(diff) |
| 73 | return diff; |
| 74 | if(c == 0) |
| 75 | return 0; |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | |
| 80 | int strncmp(const char *string1, const char *string2, int count) |
| 81 | { |
| 82 | int diff, c; |
| 83 | while(count-- > 0) |
| 84 | { |
| 85 | diff = *string1++ - (c = *string2++); |
| 86 | if(diff) |
| 87 | return diff; |
| 88 | if(c == 0) |
| 89 | return 0; |
| 90 | } |
| 91 | return 0; |
| 92 | } |
| 93 | |
| 94 | |
| 95 | char *strstr(const char *string, const char *find) |
| 96 | { |
| 97 | int i; |
| 98 | for(;;) |
| 99 | { |
| 100 | for(i = 0; string[i] == find[i] && find[i]; ++i) ; |
| 101 | if(find[i] == 0) |
| 102 | return (char*)string; |
| 103 | if(*string++ == 0) |
| 104 | return NULL; |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | |
| 109 | int strlen(const char *string) |
| 110 | { |
| 111 | const char *base=string; |
| 112 | while(*string++) ; |
| 113 | return string - base - 1; |
| 114 | } |
| 115 | |
| 116 | |
| 117 | void *memcpy(void *dst, const void *src, unsigned long bytes) |
| 118 | { |
| 119 | if(((uint32)dst | (uint32)src | bytes) & 3) |
| 120 | { |
| 121 | uint8 *Dst = (uint8*)dst, *Src = (uint8*)src; |
| 122 | while((int)bytes-- > 0) |
| 123 | *Dst++ = *Src++; |
| 124 | } |
| 125 | else |
| 126 | { |
| 127 | uint32 *Dst32 = (uint32*)dst, *Src32 = (uint32*)src; |
| 128 | bytes >>= 2; |
| 129 | while((int)bytes-- > 0) |
| 130 | *Dst32++ = *Src32++; |
| 131 | } |
| 132 | return dst; |
| 133 | } |
| 134 | |
| 135 | |
| 136 | void *memmove(void *dst, const void *src, unsigned long bytes) |
| 137 | { |
| 138 | uint8 *Dst = (uint8*)dst; |
| 139 | uint8 *Src = (uint8*)src; |
| 140 | if(Dst < Src) |
| 141 | { |
| 142 | while((int)bytes-- > 0) |
| 143 | *Dst++ = *Src++; |
| 144 | } |
| 145 | else |
| 146 | { |
| 147 | Dst += bytes; |
| 148 | Src += bytes; |
| 149 | while((int)bytes-- > 0) |
| 150 | *--Dst = *--Src; |
| 151 | } |
| 152 | return dst; |
| 153 | } |
| 154 | |
| 155 | |
| 156 | int memcmp(const void *cs, const void *ct, unsigned long bytes) |
| 157 | { |
| 158 | uint8 *Dst = (uint8*)cs; |
| 159 | uint8 *Src = (uint8*)ct; |
| 160 | int diff; |
| 161 | while((int)bytes-- > 0) |
| 162 | { |
| 163 | diff = *Dst++ - *Src++; |
| 164 | if(diff) |
| 165 | return diff; |
| 166 | } |
| 167 | return 0; |
| 168 | } |
| 169 | |
| 170 | |
| 171 | void *memset(void *dst, int c, unsigned long bytes) |
| 172 | { |
| 173 | uint8 *Dst = (uint8*)dst; |
| 174 | while((int)bytes-- > 0) |
| 175 | *Dst++ = (uint8)c; |
| 176 | return dst; |
| 177 | } |
| 178 | |
| 179 | |
| 180 | int abs(int n) |
| 181 | { |
| 182 | return n>=0 ? n : -n; |
| 183 | } |
| 184 | |
| 185 | |
| 186 | static uint32 Rand1=0x1f2bcda3, Rand2=0xdeafbeef, Rand3=0xc5134306; |
| 187 | int rand(void) |
| 188 | { |
| 189 | int shift; |
| 190 | Rand1 += 0x13423123 + Rand2; |
| 191 | Rand2 += 0x2312fdea + Rand3; |
| 192 | Rand3 += 0xf2a12de1; |
| 193 | shift = Rand3 & 31; |
| 194 | Rand1 = (Rand1 << (32 - shift)) | (Rand1 >> shift); |
| 195 | Rand3 ^= Rand1; |
| 196 | shift = (Rand3 >> 8) & 31; |
| 197 | Rand2 = (Rand2 << (32 - shift)) | (Rand2 >> shift); |
| 198 | return Rand1; |
| 199 | } |
| 200 | |
| 201 | |
| 202 | void srand(unsigned int seed) |
| 203 | { |
| 204 | Rand1 = seed; |
| 205 | } |
| 206 | |
| 207 | |
| 208 | long strtol(const char *s, char **end, int base) |
| 209 | { |
| 210 | int i; |
| 211 | unsigned long ch, value=0, neg=0; |
| 212 | |
| 213 | if(s[0] == '-') |
| 214 | { |
| 215 | neg = 1; |
| 216 | ++s; |
| 217 | } |
| 218 | if(s[0] == '0' && s[1] == 'x') |
| 219 | { |
| 220 | base = 16; |
| 221 | s += 2; |
| 222 | } |
| 223 | for(i = 0; i <= 8; ++i) |
| 224 | { |
| 225 | ch = *s++; |
| 226 | if('0' <= ch && ch <= '9') |
| 227 | ch -= '0'; |
| 228 | else if('A' <= ch && ch <= 'Z') |
| 229 | ch = ch - 'A' + 10; |
| 230 | else if('a' <= ch && ch <= 'z') |
| 231 | ch = ch - 'a' + 10; |
| 232 | else |
| 233 | break; |
| 234 | value = value * base + ch; |
| 235 | } |
| 236 | if(end) |
| 237 | *end = (char*)s - 1; |
| 238 | if(neg) |
| 239 | value = -(int)value; |
| 240 | return value; |
| 241 | } |
| 242 | |
| 243 | |
| 244 | int atoi(const char *s) |
| 245 | { |
| 246 | return strtol(s, NULL, 10); |
| 247 | } |
| 248 | |
| 249 | |
| 250 | char *itoa(int num, char *dst, int base) |
| 251 | { |
| 252 | int digit, negate=0, place; |
| 253 | char c, text[20]; |
| 254 | |
| 255 | if(base == 10 && num < 0) |
| 256 | { |
| 257 | num = -num; |
| 258 | negate = 1; |
| 259 | } |
| 260 | text[16] = 0; |
| 261 | for(place = 15; place >= 0; --place) |
| 262 | { |
| 263 | digit = (unsigned int)num % (unsigned int)base; |
| 264 | if(num == 0 && place < 15 && base == 10 && negate) |
| 265 | { |
| 266 | c = '-'; |
| 267 | negate = 0; |
| 268 | } |
| 269 | else if(digit < 10) |
| 270 | c = (char)('0' + digit); |
| 271 | else |
| 272 | c = (char)('a' + digit - 10); |
| 273 | text[place] = c; |
| 274 | num = (unsigned int)num / (unsigned int)base; |
| 275 | if(num == 0 && negate == 0) |
| 276 | break; |
| 277 | } |
| 278 | strcpy(dst, text + place); |
| 279 | return dst; |
| 280 | } |
| 281 | |
| 282 | |
| 283 | int sprintf(char *s, const char *format, |
| 284 | int arg0, int arg1, int arg2, int arg3, |
| 285 | int arg4, int arg5, int arg6, int arg7) |
| 286 | { |
| 287 | int argv[8]; |
| 288 | int argc=0, width, length; |
| 289 | char f, text[20], fill; |
| 290 | |
| 291 | argv[0] = arg0; argv[1] = arg1; argv[2] = arg2; argv[3] = arg3; |
| 292 | argv[4] = arg4; argv[5] = arg5; argv[6] = arg6; argv[7] = arg7; |
| 293 | |
| 294 | for(;;) |
| 295 | { |
| 296 | f = *format++; |
| 297 | if(f == 0) |
| 298 | return argc; |
| 299 | else if(f == '%') |
| 300 | { |
| 301 | width = 0; |
| 302 | fill = ' '; |
| 303 | f = *format++; |
| 304 | while('0' <= f && f <= '9') |
| 305 | { |
| 306 | width = width * 10 + f - '0'; |
| 307 | f = *format++; |
| 308 | } |
| 309 | if(f == '.') |
| 310 | { |
| 311 | fill = '0'; |
| 312 | f = *format++; |
| 313 | } |
| 314 | if(f == 0) |
| 315 | return argc; |
| 316 | |
| 317 | if(f == 'd') |
| 318 | { |
| 319 | memset(s, fill, width); |
| 320 | itoa(argv[argc++], text, 10); |
| 321 | length = (int)strlen(text); |
| 322 | if(width < length) |
| 323 | width = length; |
| 324 | strcpy(s + width - length, text); |
| 325 | } |
| 326 | else if(f == 'x' || f == 'f') |
| 327 | { |
| 328 | memset(s, '0', width); |
| 329 | itoa(argv[argc++], text, 16); |
| 330 | length = (int)strlen(text); |
| 331 | if(width < length) |
| 332 | width = length; |
| 333 | strcpy(s + width - length, text); |
| 334 | } |
| 335 | else if(f == 'c') |
| 336 | { |
| 337 | *s++ = (char)argv[argc++]; |
| 338 | *s = 0; |
| 339 | } |
| 340 | else if(f == 's') |
| 341 | { |
| 342 | length = strlen((char*)argv[argc]); |
| 343 | if(width > length) |
| 344 | { |
| 345 | memset(s, ' ', width - length); |
| 346 | s += width - length; |
| 347 | } |
| 348 | strcpy(s, (char*)argv[argc++]); |
| 349 | } |
| 350 | s += strlen(s); |
| 351 | } |
| 352 | else |
| 353 | { |
| 354 | if(f == '\n') |
| 355 | *s++ = '\r'; |
| 356 | *s++ = f; |
| 357 | if(f == '\r' && *format == '\n') |
| 358 | *s++ = *format++; |
| 359 | } |
| 360 | *s = 0; |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | |
| 365 | int sscanf(const char *s, const char *format, |
| 366 | int arg0, int arg1, int arg2, int arg3, |
| 367 | int arg4, int arg5, int arg6, int arg7) |
| 368 | { |
| 369 | int argv[8]; |
| 370 | int argc=0; |
| 371 | char f, *ptr; |
| 372 | |
| 373 | argv[0] = arg0; argv[1] = arg1; argv[2] = arg2; argv[3] = arg3; |
| 374 | argv[4] = arg4; argv[5] = arg5; argv[6] = arg6; argv[7] = arg7; |
| 375 | |
| 376 | for(;;) |
| 377 | { |
| 378 | if(*s == 0) |
| 379 | return argc; |
| 380 | f = *format++; |
| 381 | if(f == 0) |
| 382 | return argc; |
| 383 | else if(f == '%') |
| 384 | { |
| 385 | while(isspace(*s)) |
| 386 | ++s; |
| 387 | f = *format++; |
| 388 | if(f == 0) |
| 389 | return argc; |
| 390 | if(f == 'd') |
| 391 | *(int*)argv[argc++] = strtol(s, (char**)&s, 10); |
| 392 | else if(f == 'x') |
| 393 | *(int*)argv[argc++] = strtol(s, (char**)&s, 16); |
| 394 | else if(f == 'c') |
| 395 | *(char*)argv[argc++] = *s++; |
| 396 | else if(f == 's') |
| 397 | { |
| 398 | ptr = (char*)argv[argc++]; |
| 399 | while(!isspace(*s)) |
| 400 | *ptr++ = *s++; |
| 401 | *ptr = 0; |
| 402 | } |
| 403 | } |
| 404 | else |
| 405 | { |
| 406 | while(*s && *s != f) |
| 407 | ++s; |
| 408 | if(*s) |
| 409 | ++s; |
| 410 | } |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | |
| 415 | #ifdef INCLUDE_DUMP |
| 416 | /*********************** dump ***********************/ |
| 417 | void dump(const unsigned char *data, int length) |
| 418 | { |
| 419 | int i, index=0, value; |
| 420 | char string[80]; |
| 421 | memset(string, 0, sizeof(string)); |
| 422 | for(i = 0; i < length; ++i) |
| 423 | { |
| 424 | if((i & 15) == 0) |
| 425 | { |
| 426 | if(strlen(string)) |
| 427 | printf("%s\n", string); |
| 428 | printf("%4x ", i); |
| 429 | memset(string, 0, sizeof(string)); |
| 430 | index = 0; |
| 431 | } |
| 432 | value = data[i]; |
| 433 | printf("%2x ", value); |
| 434 | if(isprint(value)) |
| 435 | string[index] = (char)value; |
| 436 | else |
| 437 | string[index] = '.'; |
| 438 | ++index; |
| 439 | } |
| 440 | for(; index < 16; ++index) |
| 441 | printf(" "); |
| 442 | printf("%s\n", string); |
| 443 | } |
| 444 | #endif //INCLUDE_DUMP |
| 445 | |
| 446 | |
| 447 | #ifdef INCLUDE_QSORT |
| 448 | /*********************** qsort ***********************/ |
| 449 | static void QsortSwap(char *base, long left, long right, long size) |
| 450 | { |
| 451 | int temp, i; |
| 452 | char *ptrLeft, *ptrRight; |
| 453 | ptrLeft = base + left * size; |
| 454 | ptrRight = base + right * size; |
| 455 | for(i = 0; i < size; ++i) |
| 456 | { |
| 457 | temp = ptrLeft[i]; |
| 458 | ptrLeft[i] = ptrRight[i]; |
| 459 | ptrRight[i] = (char)temp; |
| 460 | } |
| 461 | } |
| 462 | |
| 463 | |
| 464 | //Modified from K&R |
| 465 | static void qsort2(void *base, long left, long right, long size, |
| 466 | int (*cmp)(const void *,const void *)) |
| 467 | { |
| 468 | int i, last; |
| 469 | char *base2=(char*)base, *pivot; |
| 470 | if(left >= right) |
| 471 | return; |
| 472 | QsortSwap(base2, left, (left + right)/2, size); |
| 473 | last = left; |
| 474 | pivot = &base2[left*size]; |
| 475 | for(i = left + 1; i <= right; ++i) |
| 476 | { |
| 477 | if(cmp(&base2[i*size], pivot) < 0) |
| 478 | QsortSwap(base2, ++last, i, size); |
| 479 | } |
| 480 | QsortSwap(base2, left, last, size); |
| 481 | qsort2(base, left, last-1, size, cmp); |
| 482 | qsort2(base, last+1, right, size, cmp); |
| 483 | } |
| 484 | |
| 485 | |
| 486 | void qsort(void *base, |
| 487 | long n, |
| 488 | long size, |
| 489 | int (*cmp)(const void *,const void *)) |
| 490 | { |
| 491 | qsort2(base, 0, n-1, size, cmp); |
| 492 | } |
| 493 | |
| 494 | |
| 495 | void *bsearch(const void *key, |
| 496 | const void *base, |
| 497 | long n, |
| 498 | long size, |
| 499 | int (*cmp)(const void *,const void *)) |
| 500 | { |
| 501 | long cond, low=0, high=n-1, mid; |
| 502 | char *base2=(char*)base; |
| 503 | while(low <= high) |
| 504 | { |
| 505 | mid = (low + high)/2; |
| 506 | cond = cmp(key, &base2[mid*size]); |
| 507 | if(cond < 0) |
| 508 | high = mid - 1; |
| 509 | else if(cond > 0) |
| 510 | low = mid + 1; |
| 511 | else |
| 512 | return &base2[mid * size]; |
| 513 | } |
| 514 | return NULL; |
| 515 | } |
| 516 | #endif //INCLUDE_QSORT |
| 517 | |
| 518 | |
| 519 | #ifdef INCLUDE_TIMELIB |
| 520 | /************************* time.h ***********************/ |
| 521 | #define SEC_PER_YEAR (365L*24*60*60) |
| 522 | #define SEC_PER_DAY (24L*60*60) |
| 523 | //typedef unsigned long time_t; //start at 1/1/80 |
| 524 | //struct tm { |
| 525 | // int tm_sec; //(0,59) |
| 526 | // int tm_min; //(0,59) |
| 527 | // int tm_hour; //(0,23) |
| 528 | // int tm_mday; //(1,31) |
| 529 | // int tm_mon; //(0,11) |
| 530 | // int tm_year; //(0,n) from 1900 |
| 531 | // int tm_wday; //(0,6) calculated |
| 532 | // int tm_yday; //(0,365) calculated |
| 533 | // int tm_isdst; //hour adjusted for day light savings |
| 534 | //}; |
| 535 | static const unsigned short DaysUntilMonth[]= |
| 536 | {0,31,59,90,120,151,181,212,243,273,304,334,365}; |
| 537 | static const unsigned short DaysInMonth[]= |
| 538 | {31,28,31,30,31,30,31,31,30,31,30,31}; |
| 539 | static time_t DstTimeIn, DstTimeOut; |
| 540 | |
| 541 | |
| 542 | /* Leap year if divisible by 4. Centenary years should only be |
| 543 | leap-years if they were divisible by 400. */ |
| 544 | static int IsLeapYear(int year) |
| 545 | { |
| 546 | return(((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)); |
| 547 | } |
| 548 | |
| 549 | time_t mktime(struct tm *tp) |
| 550 | { |
| 551 | time_t seconds; |
| 552 | unsigned long days, y, year; |
| 553 | |
| 554 | days = tp->tm_mday - 1 + DaysUntilMonth[tp->tm_mon] + |
| 555 | 365 * (tp->tm_year - 80); |
| 556 | seconds = (unsigned long)tp->tm_sec + 60L * (tp->tm_min + |
| 557 | 60L * (tp->tm_hour + 24L * days)); |
| 558 | if(tp->tm_isdst) |
| 559 | seconds -= 60 * 60; |
| 560 | year = 1900 + tp->tm_year - (tp->tm_mon < 2); |
| 561 | for(y = 1980; y <= year; y += 4) |
| 562 | { |
| 563 | if(y % 100 != 0 || y % 400 == 0) |
| 564 | seconds += SEC_PER_DAY; |
| 565 | } |
| 566 | return seconds; |
| 567 | } |
| 568 | |
| 569 | |
| 570 | void gmtime_r(const time_t *tp, struct tm *out) |
| 571 | { |
| 572 | time_t seconds, delta, secondsIn=*tp; |
| 573 | int isLeapYear; |
| 574 | unsigned long year, month; |
| 575 | |
| 576 | out->tm_isdst = 0; |
| 577 | if(DstTimeIn <= secondsIn && secondsIn < DstTimeOut) |
| 578 | { |
| 579 | secondsIn += 60 * 60; |
| 580 | out->tm_isdst = 1; |
| 581 | } |
| 582 | seconds = secondsIn; |
| 583 | for(year = 0; ; ++year) |
| 584 | { |
| 585 | delta = SEC_PER_YEAR + IsLeapYear(1980 + year) * SEC_PER_DAY; |
| 586 | if(seconds >= delta) |
| 587 | seconds -= delta; |
| 588 | else |
| 589 | break; |
| 590 | } |
| 591 | out->tm_year = year + 80; |
| 592 | isLeapYear = IsLeapYear(1980 + year); |
| 593 | for(month = 0; ; ++month) |
| 594 | { |
| 595 | delta = SEC_PER_DAY * (DaysInMonth[month] + (isLeapYear && (month == 1))); |
| 596 | if(seconds >= delta) |
| 597 | seconds -= delta; |
| 598 | else |
| 599 | break; |
| 600 | } |
| 601 | out->tm_mon = month; |
| 602 | out->tm_mday = seconds / SEC_PER_DAY; |
| 603 | out->tm_yday = DaysUntilMonth[month] + out->tm_mday; |
| 604 | seconds -= out->tm_mday * SEC_PER_DAY; |
| 605 | ++out->tm_mday; |
| 606 | out->tm_hour = seconds / (60 * 60); |
| 607 | seconds -= out->tm_hour * (60 * 60); |
| 608 | out->tm_min = seconds / 60; |
| 609 | seconds -= out->tm_min * 60; |
| 610 | out->tm_sec = seconds; |
| 611 | seconds = secondsIn % (SEC_PER_DAY * 7); |
| 612 | out->tm_wday = (seconds / SEC_PER_DAY + 2) % 7; /* 1/1/80 is a Tue */ |
| 613 | //printf("%4.d/%2.d/%2.d:%2.d:%2.d:%2.d\n", |
| 614 | // out->tm_year+1900, out->tm_mon+1, out->tm_mday, |
| 615 | // out->tm_hour, out->tm_min, out->tm_sec); |
| 616 | } |
| 617 | |
| 618 | |
| 619 | void gmtimeDst(time_t dstTimeIn, time_t dstTimeOut) |
| 620 | { |
| 621 | DstTimeIn = dstTimeIn; |
| 622 | DstTimeOut = dstTimeOut; |
| 623 | } |
| 624 | |
| 625 | |
| 626 | //DST from 2am on the second Sunday in March to 2am first Sunday in November |
| 627 | void gmtimeDstSet(time_t *tp, time_t *dstTimeIn, time_t *dstTimeOut) |
| 628 | { |
| 629 | time_t seconds, timeIn, timeOut; |
| 630 | struct tm tmDate; |
| 631 | int year, days; |
| 632 | |
| 633 | DstTimeIn = 0; |
| 634 | DstTimeOut = 0; |
| 635 | gmtime_r(tp, &tmDate); |
| 636 | year = tmDate.tm_year; |
| 637 | |
| 638 | //March 1, year, 2AM -> second Sunday |
| 639 | tmDate.tm_year = year; |
| 640 | tmDate.tm_mon = 2; |
| 641 | tmDate.tm_mday = 1; |
| 642 | tmDate.tm_hour = 2; |
| 643 | tmDate.tm_min = 0; |
| 644 | tmDate.tm_sec = 0; |
| 645 | seconds = mktime(&tmDate); |
| 646 | gmtime_r(&seconds, &tmDate); |
| 647 | days = 7 - tmDate.tm_wday + 7; |
| 648 | *dstTimeIn = timeIn = seconds + days * SEC_PER_DAY; |
| 649 | |
| 650 | //November 1, year, 2AM -> first Sunday |
| 651 | tmDate.tm_year = year; |
| 652 | tmDate.tm_mon = 10; |
| 653 | tmDate.tm_mday = 1; |
| 654 | tmDate.tm_hour = 2; |
| 655 | tmDate.tm_min = 0; |
| 656 | tmDate.tm_sec = 0; |
| 657 | seconds = mktime(&tmDate); |
| 658 | gmtime_r(&seconds, &tmDate); |
| 659 | days = 7 - tmDate.tm_wday; |
| 660 | *dstTimeOut = timeOut = seconds + days * SEC_PER_DAY; |
| 661 | |
| 662 | DstTimeIn = timeIn; |
| 663 | DstTimeOut = timeOut; |
| 664 | } |
| 665 | #endif //INCLUDE_TIMELIB |
| 666 | |
plasma/kernel/math.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma Floating Point Library |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 3/2/06 |
| 5 | * FILENAME: math.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma Floating Point Library |
| 11 | *-------------------------------------------------------------------- |
| 12 | * IEEE_fp = sign(1) | exponent(8) | fraction(23) |
| 13 | * cos(x)=1-x^2/2!+x^4/4!-x^6/6!+... |
| 14 | * exp(x)=1+x+x^2/2!+x^3/3!+... |
| 15 | * ln(1+x)=x-x^2/2+x^3/3-x^4/4+... |
| 16 | * atan(x)=x-x^3/3+x^5/5-x^7/7+... |
| 17 | * pow(x,y)=exp(y*ln(x)) |
| 18 | * x=tan(a+b)=(tan(a)+tan(b))/(1-tan(a)*tan(b)) |
| 19 | * atan(x)=b+atan((x-atan(b))/(1+x*atan(b))) |
| 20 | * ln(a*x)=ln(a)+ln(x); ln(x^n)=n*ln(x) |
| 21 | *--------------------------------------------------------------------*/ |
| 22 | #include "rtos.h" |
| 23 | |
| 24 | //#define USE_SW_MULT |
| 25 | #if !defined(WIN32) && !defined(USE_SW_MULT) |
| 26 | #define USE_MULT64 |
| 27 | #endif |
| 28 | |
| 29 | #define PI ((float)3.1415926) |
| 30 | #define PI_2 ((float)(PI/2.0)) |
| 31 | #define PI2 ((float)(PI*2.0)) |
| 32 | |
| 33 | #define FtoL(X) (*(unsigned long*)&(X)) |
| 34 | #define LtoF(X) (*(float*)&(X)) |
| 35 | |
| 36 | |
| 37 | float FP_Neg(float a_fp) |
| 38 | { |
| 39 | unsigned long a; |
| 40 | a = FtoL(a_fp); |
| 41 | a ^= 0x80000000; |
| 42 | return LtoF(a); |
| 43 | } |
| 44 | |
| 45 | |
| 46 | float FP_Add(float a_fp, float b_fp) |
| 47 | { |
| 48 | unsigned long a, b, c; |
| 49 | unsigned long as, bs, cs; //sign |
| 50 | long ae, af, be, bf, ce, cf; //exponent and fraction |
| 51 | a = FtoL(a_fp); |
| 52 | b = FtoL(b_fp); |
| 53 | as = a >> 31; //sign |
| 54 | ae = (a >> 23) & 0xff; //exponent |
| 55 | af = 0x00800000 | (a & 0x007fffff); //fraction |
| 56 | bs = b >> 31; |
| 57 | be = (b >> 23) & 0xff; |
| 58 | bf = 0x00800000 | (b & 0x007fffff); |
| 59 | if(ae > be) |
| 60 | { |
| 61 | if(ae - be < 30) |
| 62 | bf >>= ae - be; |
| 63 | else |
| 64 | bf = 0; |
| 65 | ce = ae; |
| 66 | } |
| 67 | else |
| 68 | { |
| 69 | if(be - ae < 30) |
| 70 | af >>= be - ae; |
| 71 | else |
| 72 | af = 0; |
| 73 | ce = be; |
| 74 | } |
| 75 | cf = (as ? -af : af) + (bs ? -bf : bf); |
| 76 | cs = cf < 0; |
| 77 | cf = cf>=0 ? cf : -cf; |
| 78 | if(cf == 0) |
| 79 | return LtoF(cf); |
| 80 | while(cf & 0xff000000) |
| 81 | { |
| 82 | ++ce; |
| 83 | cf >>= 1; |
| 84 | } |
| 85 | while((cf & 0xff800000) == 0) |
| 86 | { |
| 87 | --ce; |
| 88 | cf <<= 1; |
| 89 | } |
| 90 | c = (cs << 31) | (ce << 23) | (cf & 0x007fffff); |
| 91 | if(ce < 1) |
| 92 | c = 0; |
| 93 | return LtoF(c); |
| 94 | } |
| 95 | |
| 96 | |
| 97 | float FP_Sub(float a_fp, float b_fp) |
| 98 | { |
| 99 | return FP_Add(a_fp, FP_Neg(b_fp)); |
| 100 | } |
| 101 | |
| 102 | |
| 103 | float FP_Mult(float a_fp, float b_fp) |
| 104 | { |
| 105 | unsigned long a, b, c; |
| 106 | unsigned long as, af, bs, bf, cs, cf; |
| 107 | long ae, be, ce; |
| 108 | #ifndef USE_MULT64 |
| 109 | unsigned long a2, a1, b2, b1, med1, med2; |
| 110 | #endif |
| 111 | unsigned long hi, lo; |
| 112 | a = FtoL(a_fp); |
| 113 | b = FtoL(b_fp); |
| 114 | as = a >> 31; |
| 115 | ae = (a >> 23) & 0xff; |
| 116 | af = 0x00800000 | (a & 0x007fffff); |
| 117 | bs = b >> 31; |
| 118 | be = (b >> 23) & 0xff; |
| 119 | bf = 0x00800000 | (b & 0x007fffff); |
| 120 | cs = as ^ bs; |
| 121 | #ifndef USE_MULT64 |
| 122 | a1 = af & 0xffff; |
| 123 | a2 = af >> 16; |
| 124 | b1 = bf & 0xffff; |
| 125 | b2 = bf >> 16; |
| 126 | lo = a1 * b1; |
| 127 | med1 = a2 * b1 + (lo >> 16); |
| 128 | med2 = a1 * b2; |
| 129 | hi = a2 * b2 + (med1 >> 16) + (med2 >> 16); |
| 130 | med1 = (med1 & 0xffff) + (med2 & 0xffff); |
| 131 | hi += (med1 >> 16); |
| 132 | lo = (med1 << 16) | (lo & 0xffff); |
| 133 | #else |
| 134 | lo = OS_AsmMult(af, bf, &hi); |
| 135 | #endif |
| 136 | cf = (hi << 9) | (lo >> 23); |
| 137 | ce = ae + be - 0x80 + 1; |
| 138 | if(cf == 0) |
| 139 | return LtoF(cf); |
| 140 | while(cf & 0xff000000) |
| 141 | { |
| 142 | ++ce; |
| 143 | cf >>= 1; |
| 144 | } |
| 145 | c = (cs << 31) | (ce << 23) | (cf & 0x007fffff); |
| 146 | if(ce < 1) |
| 147 | c = 0; |
| 148 | return LtoF(c); |
| 149 | } |
| 150 | |
| 151 | |
| 152 | float FP_Div(float a_fp, float b_fp) |
| 153 | { |
| 154 | unsigned long a, b, c; |
| 155 | unsigned long as, af, bs, bf, cs, cf; |
| 156 | unsigned long a1, b1; |
| 157 | #ifndef USE_MULT64 |
| 158 | unsigned long a2, b2, med1, med2; |
| 159 | #endif |
| 160 | unsigned long hi, lo; |
| 161 | long ae, be, ce, d; |
| 162 | a = FtoL(a_fp); |
| 163 | b = FtoL(b_fp); |
| 164 | as = a >> 31; |
| 165 | ae = (a >> 23) & 0xff; |
| 166 | af = 0x00800000 | (a & 0x007fffff); |
| 167 | bs = b >> 31; |
| 168 | be = (b >> 23) & 0xff; |
| 169 | bf = 0x00800000 | (b & 0x007fffff); |
| 170 | cs = as ^ bs; |
| 171 | ce = ae - (be - 0x80) + 6 - 8; |
| 172 | a1 = af << 4; //8 |
| 173 | b1 = bf >> 8; |
| 174 | cf = a1 / b1; |
| 175 | cf <<= 12; //8 |
| 176 | #if 1 /*non-quick*/ |
| 177 | #ifndef USE_MULT64 |
| 178 | a1 = cf & 0xffff; |
| 179 | a2 = cf >> 16; |
| 180 | b1 = bf & 0xffff; |
| 181 | b2 = bf >> 16; |
| 182 | lo = a1 * b1; |
| 183 | med1 =a2 * b1 + (lo >> 16); |
| 184 | med2 = a1 * b2; |
| 185 | hi = a2 * b2 + (med1 >> 16) + (med2 >> 16); |
| 186 | med1 = (med1 & 0xffff) + (med2 & 0xffff); |
| 187 | hi += (med1 >> 16); |
| 188 | lo = (med1 << 16) | (lo & 0xffff); |
| 189 | #else |
| 190 | lo = OS_AsmMult(cf, bf, &hi); |
| 191 | #endif |
| 192 | lo = (hi << 8) | (lo >> 24); |
| 193 | d = af - lo; //remainder |
| 194 | assert(-0xffff < d && d < 0xffff); |
| 195 | d <<= 16; |
| 196 | b1 = bf >> 8; |
| 197 | d = d / (long)b1; |
| 198 | cf += d; |
| 199 | #endif |
| 200 | if(cf == 0) |
| 201 | return LtoF(cf); |
| 202 | while(cf & 0xff000000) |
| 203 | { |
| 204 | ++ce; |
| 205 | cf >>= 1; |
| 206 | } |
| 207 | if(ce < 0) |
| 208 | ce = 0; |
| 209 | c = (cs << 31) | (ce << 23) | (cf & 0x007fffff); |
| 210 | if(ce < 1) |
| 211 | c = 0; |
| 212 | return LtoF(c); |
| 213 | } |
| 214 | |
| 215 | |
| 216 | long FP_ToLong(float a_fp) |
| 217 | { |
| 218 | unsigned long a; |
| 219 | unsigned long as; |
| 220 | long ae; |
| 221 | long af, shift; |
| 222 | a = FtoL(a_fp); |
| 223 | as = a >> 31; |
| 224 | ae = (a >> 23) & 0xff; |
| 225 | af = 0x00800000 | (a & 0x007fffff); |
| 226 | af <<= 7; |
| 227 | shift = -(ae - 0x80 - 29); |
| 228 | if(shift > 0) |
| 229 | { |
| 230 | if(shift < 31) |
| 231 | af >>= shift; |
| 232 | else |
| 233 | af = 0; |
| 234 | } |
| 235 | af = as ? -af: af; |
| 236 | return af; |
| 237 | } |
| 238 | |
| 239 | |
| 240 | float FP_ToFloat(long af) |
| 241 | { |
| 242 | unsigned long a; |
| 243 | unsigned long as, ae; |
| 244 | as = af>=0 ? 0: 1; |
| 245 | af = af>=0 ? af: -af; |
| 246 | ae = 0x80 + 22; |
| 247 | if(af == 0) |
| 248 | return LtoF(af); |
| 249 | while(af & 0xff000000) |
| 250 | { |
| 251 | ++ae; |
| 252 | af >>= 1; |
| 253 | } |
| 254 | while((af & 0xff800000) == 0) |
| 255 | { |
| 256 | --ae; |
| 257 | af <<= 1; |
| 258 | } |
| 259 | a = (as << 31) | (ae << 23) | (af & 0x007fffff); |
| 260 | return LtoF(a); |
| 261 | } |
| 262 | |
| 263 | |
| 264 | //0 iff a==b; 1 iff a>b; -1 iff a<b |
| 265 | int FP_Cmp(float a_fp, float b_fp) |
| 266 | { |
| 267 | unsigned long a, b; |
| 268 | unsigned long as, ae, af, bs, be, bf; |
| 269 | int gt; |
| 270 | a = FtoL(a_fp); |
| 271 | b = FtoL(b_fp); |
| 272 | if(a == b) |
| 273 | return 0; |
| 274 | as = a >> 31; |
| 275 | bs = b >> 31; |
| 276 | if(as > bs) |
| 277 | return -1; |
| 278 | if(as < bs) |
| 279 | return 1; |
| 280 | gt = as ? -1 : 1; |
| 281 | ae = (a >> 23) & 0xff; |
| 282 | be = (b >> 23) & 0xff; |
| 283 | if(ae > be) |
| 284 | return gt; |
| 285 | if(ae < be) |
| 286 | return -gt; |
| 287 | af = 0x00800000 | (a & 0x007fffff); |
| 288 | bf = 0x00800000 | (b & 0x007fffff); |
| 289 | if(af > bf) |
| 290 | return gt; |
| 291 | return -gt; |
| 292 | } |
| 293 | |
| 294 | |
| 295 | int __ltsf2(float a, float b) |
| 296 | { |
| 297 | return FP_Cmp(a, b); |
| 298 | } |
| 299 | |
| 300 | int __lesf2(float a, float b) |
| 301 | { |
| 302 | return FP_Cmp(a, b); |
| 303 | } |
| 304 | |
| 305 | int __gtsf2(float a, float b) |
| 306 | { |
| 307 | return FP_Cmp(a, b); |
| 308 | } |
| 309 | |
| 310 | int __gesf2(float a, float b) |
| 311 | { |
| 312 | return FP_Cmp(a, b); |
| 313 | } |
| 314 | |
| 315 | int __eqsf2(float a, float b) |
| 316 | { |
| 317 | return FtoL(a) != FtoL(b); |
| 318 | } |
| 319 | |
| 320 | int __nesf2(float a, float b) |
| 321 | { |
| 322 | return FtoL(a) != FtoL(b); |
| 323 | } |
| 324 | |
| 325 | |
| 326 | float FP_Sqrt(float a) |
| 327 | { |
| 328 | float x1, y1, x2, y2, x3; |
| 329 | long i; |
| 330 | x1 = FP_ToFloat(1); |
| 331 | y1 = FP_Sub(FP_Mult(x1, x1), a); //y1=x1*x1-a; |
| 332 | x2 = FP_ToFloat(100); |
| 333 | y2 = FP_Sub(FP_Mult(x2, x2), a); |
| 334 | for(i = 0; i < 10; ++i) |
| 335 | { |
| 336 | if(FtoL(y1) == FtoL(y2)) |
| 337 | return x2; |
| 338 | //x3=x2-(x1-x2)*y2/(y1-y2); |
| 339 | x3 = FP_Sub(x2, FP_Div(FP_Mult(FP_Sub(x1, x2), y2), FP_Sub(y1, y2))); |
| 340 | x1 = x2; |
| 341 | y1 = y2; |
| 342 | x2 = x3; |
| 343 | y2 = FP_Sub(FP_Mult(x2, x2), a); |
| 344 | } |
| 345 | return x2; |
| 346 | } |
| 347 | |
| 348 | |
| 349 | float FP_Cos(float rad) |
| 350 | { |
| 351 | int n; |
| 352 | float answer, x2, top, bottom, sign; |
| 353 | while(FP_Cmp(rad, PI2) > 0) |
| 354 | rad = FP_Sub(rad, PI2); |
| 355 | while(FP_Cmp(rad, (float)0.0) < 0) |
| 356 | rad = FP_Add(rad, PI2); |
| 357 | answer = 1.0; |
| 358 | sign = 1.0; |
| 359 | if(FP_Cmp(rad, PI) >= 0) |
| 360 | { |
| 361 | rad = FP_Sub(rad, PI); |
| 362 | sign = FP_ToFloat(-1); |
| 363 | } |
| 364 | if(FP_Cmp(rad, PI_2) >= 0) |
| 365 | { |
| 366 | rad = FP_Sub(PI, rad); |
| 367 | sign = FP_Neg(sign); |
| 368 | } |
| 369 | x2 = FP_Mult(rad, rad); |
| 370 | top = 1.0; |
| 371 | bottom = 1.0; |
| 372 | for(n = 2; n < 12; n += 2) |
| 373 | { |
| 374 | top = FP_Mult(top, FP_Neg(x2)); |
| 375 | bottom = FP_Mult(bottom, FP_ToFloat((n - 1) * n)); |
| 376 | answer = FP_Add(answer, FP_Div(top, bottom)); |
| 377 | } |
| 378 | return FP_Mult(answer, sign); |
| 379 | } |
| 380 | |
| 381 | |
| 382 | float FP_Sin(float rad) |
| 383 | { |
| 384 | const float pi_2=(float)(PI/2.0); |
| 385 | return FP_Cos(FP_Sub(rad, pi_2)); |
| 386 | } |
| 387 | |
| 388 | |
| 389 | float FP_Atan(float x) |
| 390 | { |
| 391 | const float b=(float)(PI/8.0); |
| 392 | const float atan_b=(float)0.37419668; //atan(b); |
| 393 | int n; |
| 394 | float answer, x2, top; |
| 395 | if(FP_Cmp(x, (float)0.0) >= 0) |
| 396 | { |
| 397 | if(FP_Cmp(x, (float)1.0) > 0) |
| 398 | return FP_Sub(PI_2, FP_Atan(FP_Div((float)1.0, x))); |
| 399 | } |
| 400 | else |
| 401 | { |
| 402 | if(FP_Cmp(x, (float)-1.0) > 0) |
| 403 | return FP_Sub(-PI_2, FP_Atan(FP_Div((float)1.0, x))); |
| 404 | } |
| 405 | if(FP_Cmp(x, (float)0.45) > 0) |
| 406 | { |
| 407 | //answer = (x - atan_b) / (1 + x * atan_b); |
| 408 | answer = FP_Div(FP_Sub(x, atan_b), FP_Add(1.0, FP_Mult(x, atan_b))); |
| 409 | //answer = b + FP_Atan(answer) - (float)0.034633; /*FIXME fudge?*/ |
| 410 | answer = FP_Sub(FP_Add(b, FP_Atan(answer)), (float)0.034633); |
| 411 | return answer; |
| 412 | } |
| 413 | if(FP_Cmp(x, (float)-0.45) < 0) |
| 414 | { |
| 415 | x = FP_Neg(x); |
| 416 | //answer = (x - atan_b) / (1 + x * atan_b); |
| 417 | answer = FP_Div(FP_Sub(x, atan_b), FP_Add(1.0, FP_Mult(x, atan_b))); |
| 418 | //answer = b + FP_Atan(answer) - (float)0.034633; /*FIXME*/ |
| 419 | answer = FP_Sub(FP_Add(b, FP_Atan(answer)), (float)0.034633); |
| 420 | return FP_Neg(answer); |
| 421 | } |
| 422 | answer = x; |
| 423 | x2 = FP_Mult(FP_Neg(x), x); |
| 424 | top = x; |
| 425 | for(n = 3; n < 14; n += 2) |
| 426 | { |
| 427 | top = FP_Mult(top, x2); |
| 428 | answer = FP_Add(answer, FP_Div(top, FP_ToFloat(n))); |
| 429 | } |
| 430 | return answer; |
| 431 | } |
| 432 | |
| 433 | |
| 434 | float FP_Atan2(float y, float x) |
| 435 | { |
| 436 | float answer,r; |
| 437 | r = y / x; |
| 438 | answer = FP_Atan(r); |
| 439 | if(FP_Cmp(x, (float)0.0) < 0) |
| 440 | { |
| 441 | if(FP_Cmp(y, (float)0.0) > 0) |
| 442 | answer = FP_Add(answer, PI); |
| 443 | else |
| 444 | answer = FP_Sub(answer, PI); |
| 445 | } |
| 446 | return answer; |
| 447 | } |
| 448 | |
| 449 | |
| 450 | float FP_Exp(float x) |
| 451 | { |
| 452 | const float e2=(float)7.389056099; |
| 453 | const float inv_e2=(float)0.135335283; |
| 454 | float answer, top, bottom, mult; |
| 455 | int n; |
| 456 | |
| 457 | mult = 1.0; |
| 458 | while(FP_Cmp(x, (float)2.0) > 0) |
| 459 | { |
| 460 | mult = FP_Mult(mult, e2); |
| 461 | x = FP_Add(x, (float)-2.0); |
| 462 | } |
| 463 | while(FP_Cmp(x, (float)-2.0) < 0) |
| 464 | { |
| 465 | mult = FP_Mult(mult, inv_e2); |
| 466 | x = FP_Add(x, (float)2.0); |
| 467 | } |
| 468 | answer = FP_Add((float)1.0, x); |
| 469 | top = x; |
| 470 | bottom = 1.0; |
| 471 | for(n = 2; n < 15; ++n) |
| 472 | { |
| 473 | top = FP_Mult(top, x); |
| 474 | bottom = FP_Mult(bottom, FP_ToFloat(n)); |
| 475 | answer = FP_Add(answer, FP_Div(top, bottom)); |
| 476 | } |
| 477 | return FP_Mult(answer, mult); |
| 478 | } |
| 479 | |
| 480 | |
| 481 | float FP_Log(float x) |
| 482 | { |
| 483 | const float log_2=(float)0.69314718; /*log(2.0)*/ |
| 484 | int n; |
| 485 | float answer, top, add; |
| 486 | add = 0.0; |
| 487 | while(FP_Cmp(x, 16.0) > 0) |
| 488 | { |
| 489 | x = FP_Mult(x, (float)0.0625); |
| 490 | add = FP_Add(add, (float)(log_2 * 4)); |
| 491 | } |
| 492 | while(FP_Cmp(x, 1.5) > 0) |
| 493 | { |
| 494 | x = FP_Mult(x, 0.5); |
| 495 | add = FP_Add(add, log_2); |
| 496 | } |
| 497 | while(FP_Cmp(x, 0.5) < 0) |
| 498 | { |
| 499 | x = FP_Mult(x, 2.0); |
| 500 | add = FP_Sub(add, log_2); |
| 501 | } |
| 502 | x = FP_Sub(x, 1.0); |
| 503 | answer = 0.0; |
| 504 | top = -1.0; |
| 505 | for(n = 1; n < 14; ++n) |
| 506 | { |
| 507 | top = FP_Mult(top, FP_Neg(x)); |
| 508 | answer = FP_Add(answer, FP_Div(top, FP_ToFloat(n))); |
| 509 | } |
| 510 | return FP_Add(answer, add); |
| 511 | } |
| 512 | |
| 513 | |
| 514 | float FP_Pow(float x, float y) |
| 515 | { |
| 516 | return FP_Exp(y * FP_Log(x)); |
| 517 | } |
| 518 | |
| 519 | |
| 520 | /********************************************/ |
| 521 | //These five functions will only be used if the flag "-mno-mul" is enabled |
| 522 | #ifdef USE_SW_MULT |
| 523 | unsigned long __mulsi3(unsigned long a, unsigned long b) |
| 524 | { |
| 525 | unsigned long answer = 0; |
| 526 | while(b) |
| 527 | { |
| 528 | if(b & 1) |
| 529 | answer += a; |
| 530 | a <<= 1; |
| 531 | b >>= 1; |
| 532 | } |
| 533 | return answer; |
| 534 | } |
| 535 | |
| 536 | |
| 537 | static unsigned long DivideMod(unsigned long a, unsigned long b, int doMod) |
| 538 | { |
| 539 | unsigned long upper=a, lower=0; |
| 540 | int i; |
| 541 | a = b << 31; |
| 542 | for(i = 0; i < 32; ++i) |
| 543 | { |
| 544 | lower = lower << 1; |
| 545 | if(upper >= a && a && b < 2) |
| 546 | { |
| 547 | upper = upper - a; |
| 548 | lower |= 1; |
| 549 | } |
| 550 | a = ((b&2) << 30) | (a >> 1); |
| 551 | b = b >> 1; |
| 552 | } |
| 553 | if(!doMod) |
| 554 | return lower; |
| 555 | return upper; |
| 556 | } |
| 557 | |
| 558 | |
| 559 | unsigned long __udivsi3(unsigned long a, unsigned long b) |
| 560 | { |
| 561 | return DivideMod(a, b, 0); |
| 562 | } |
| 563 | |
| 564 | |
| 565 | long __divsi3(long a, long b) |
| 566 | { |
| 567 | long answer, negate=0; |
| 568 | if(a < 0) |
| 569 | { |
| 570 | a = -a; |
| 571 | negate = !negate; |
| 572 | } |
| 573 | if(b < 0) |
| 574 | { |
| 575 | b = -b; |
| 576 | negate = !negate; |
| 577 | } |
| 578 | answer = DivideMod(a, b, 0); |
| 579 | if(negate) |
| 580 | answer = -answer; |
| 581 | return answer; |
| 582 | } |
| 583 | |
| 584 | |
| 585 | unsigned long __umodsi3(unsigned long a, unsigned long b) |
| 586 | { |
| 587 | return DivideMod(a, b, 1); |
| 588 | } |
| 589 | #endif |
| 590 | |
| 591 | |
| 592 | /*************** Test *****************/ |
| 593 | #ifdef WIN32 |
| 594 | #undef _LIBC |
| 595 | #include <math.h> |
| 596 | #undef printf |
| 597 | #undef getch |
| 598 | int printf(const char *, ...); |
| 599 | struct { |
| 600 | char *name; |
| 601 | float low, high; |
| 602 | double (*func1)(double); |
| 603 | float (*func2)(float); |
| 604 | } test_info[]={ |
| 605 | {"cos", -2*PI, 2*PI, cos, FP_Cos}, |
| 606 | {"sin", -2*PI, 2*PI, sin, FP_Sin}, |
| 607 | {"atan", -3.0, 2.0, atan, FP_Atan}, |
| 608 | {"log", (float)0.01, (float)4.0, log, FP_Log}, |
| 609 | {"exp", (float)-5.01, (float)30.0, exp, FP_Exp}, |
| 610 | {"sqrt", (float)0.01, (float)1000.0, sqrt, FP_Sqrt} |
| 611 | }; |
| 612 | |
| 613 | |
| 614 | void TestMathFull(void) |
| 615 | { |
| 616 | float a, b, c, d; |
| 617 | float error1, error2, error3, error4, error5; |
| 618 | int test; |
| 619 | |
| 620 | a = PI * PI; |
| 621 | b = PI; |
| 622 | c = FP_Div(a, b); |
| 623 | printf("%10f %10f %10f %10f %10f\n", |
| 624 | (double)a, (double)b, (double)(a/b), (double)c, (double)(a/b-c)); |
| 625 | a = a * 200; |
| 626 | for(b = -(float)2.718281828*100; b < 300; b += (float)23.678) |
| 627 | { |
| 628 | c = FP_Div(a, b); |
| 629 | d = a / b - c; |
| 630 | printf("%10f %10f %10f %10f %10f\n", |
| 631 | (double)a, (double)b, (double)(a/b), (double)c, (double)(a/b-c)); |
| 632 | } |
| 633 | //getch(); |
| 634 | |
| 635 | for(test = 0; test < 6; ++test) |
| 636 | { |
| 637 | printf("\nTesting %s\n", test_info[test].name); |
| 638 | for(a = test_info[test].low; |
| 639 | a <= test_info[test].high; |
| 640 | a += (test_info[test].high-test_info[test].low)/(float)20.0) |
| 641 | { |
| 642 | b = (float)test_info[test].func1(a); |
| 643 | c = test_info[test].func2(a); |
| 644 | d = b - c; |
| 645 | printf("%s %10f %10f %10f %10f\n", test_info[test].name, a, b, c, d); |
| 646 | } |
| 647 | //getch(); |
| 648 | } |
| 649 | |
| 650 | a = FP_ToFloat((long)6.0); |
| 651 | b = FP_ToFloat((long)2.0); |
| 652 | printf("%f %f\n", (double)a, (double)b); |
| 653 | c = FP_Add(a, b); |
| 654 | printf("add %f %f\n", (double)(a + b), (double)c); |
| 655 | c = FP_Sub(a, b); |
| 656 | printf("sub %f %f\n", (double)(a - b), (double)c); |
| 657 | c = FP_Mult(a, b); |
| 658 | printf("mult %f %f\n", (double)(a * b), (double)c); |
| 659 | c = FP_Div(a, b); |
| 660 | printf("div %f %f\n", (double)(a / b), (double)c); |
| 661 | //getch(); |
| 662 | |
| 663 | for(a = (float)-13756.54; a < (float)17400.0; a += (float)64.45) |
| 664 | { |
| 665 | for(b = (float)-875.36; b < (float)935.8; b += (float)36.7) |
| 666 | { |
| 667 | error1 = (float)1.0 - (a + b) / FP_Add(a, b); |
| 668 | error2 = (float)1.0 - (a * b) / FP_Mult(a, b); |
| 669 | error3 = (float)1.0 - (a / b) / FP_Div(a, b); |
| 670 | error4 = (float)1.0 - a / FP_ToFloat(FP_ToLong(a)); |
| 671 | error5 = error1 + error2 + error3 + error4; |
| 672 | if(error5 < 0.00005) |
| 673 | continue; |
| 674 | printf("ERROR!\n"); |
| 675 | printf("a=%f b=%f\n", (double)a, (double)b); |
| 676 | printf(" a+b=%f %f\n", (double)(a+b), (double)FP_Add(a, b)); |
| 677 | printf(" a*b=%f %f\n", (double)(a*b), (double)FP_Mult(a, b)); |
| 678 | printf(" a/b=%f %f\n", (double)(a/b), (double)FP_Div(a, b)); |
| 679 | printf(" a=%f %ld %f\n", (double)a, FP_ToLong(a), |
| 680 | (double)FP_ToFloat((long)a)); |
| 681 | printf(" %f %f %f %f\n", (double)error1, (double)error2, |
| 682 | (double)error3, (double)error4); |
| 683 | //if(error5 > 0.001) |
| 684 | // getch(); |
| 685 | } |
| 686 | } |
| 687 | printf("done.\n"); |
| 688 | //getch(); |
| 689 | } |
| 690 | #endif |
| 691 | |
| 692 | |
plasma/kernel/netutil.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma TCP/IP Network Utilities |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 4/20/07 |
| 5 | * FILENAME: netutil.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma FTP server and FTP client and TFTP server and client |
| 11 | * and Telnet server. |
| 12 | *--------------------------------------------------------------------*/ |
| 13 | #undef INCLUDE_FILESYS |
| 14 | #define INCLUDE_FILESYS |
| 15 | #ifdef WIN32 |
| 16 | #include <stdio.h> |
| 17 | #include <stdlib.h> |
| 18 | #include <string.h> |
| 19 | #include <ctype.h> |
| 20 | #define _LIBC |
| 21 | #endif |
| 22 | #include "rtos.h" |
| 23 | #include "tcpip.h" |
| 24 | |
| 25 | #ifdef DLL_SETUP |
| 26 | static void ConsoleRun(IPSocket *socket, char *argv[]); |
| 27 | #endif |
| 28 | |
| 29 | //******************* FTP Server ************************ |
| 30 | typedef struct { |
| 31 | IPSocket *socket; |
| 32 | int ip, port, bytes, done, canReceive; |
| 33 | FILE *file; |
| 34 | } FtpdInfo; |
| 35 | |
| 36 | static void FtpdSender(IPSocket *socket) |
| 37 | { |
| 38 | unsigned char buf[600]; |
| 39 | int i, bytes, bytes2; |
| 40 | FtpdInfo *info = (FtpdInfo*)socket->userPtr; |
| 41 | |
| 42 | if(info == NULL || info->done) |
| 43 | return; |
| 44 | fseek(info->file, info->bytes, 0); |
| 45 | for(i = 0; i < 100000; ++i) |
| 46 | { |
| 47 | bytes = fread(buf, 1, 512, info->file); |
| 48 | bytes2 = IPWrite(socket, buf, bytes); |
| 49 | info->bytes += bytes2; |
| 50 | if(bytes != bytes2) |
| 51 | return; |
| 52 | if(bytes < 512) |
| 53 | { |
| 54 | fclose(info->file); |
| 55 | IPClose(socket); |
| 56 | info->done = 1; |
| 57 | IPPrintf(info->socket, "226 Done\r\n"); |
| 58 | return; |
| 59 | } |
| 60 | } |
| 61 | } |
| 62 | |
| 63 | |
| 64 | static void FtpdReceiver(IPSocket *socket) |
| 65 | { |
| 66 | unsigned char buf[600]; |
| 67 | int bytes, state = socket->state; |
| 68 | FtpdInfo *info = (FtpdInfo*)socket->userPtr; |
| 69 | |
| 70 | if(info == NULL || info->done) |
| 71 | return; |
| 72 | do |
| 73 | { |
| 74 | bytes = IPRead(socket, buf, sizeof(buf)); |
| 75 | fwrite(buf, 1, bytes, info->file); |
| 76 | } while(bytes); |
| 77 | |
| 78 | if(state > IP_TCP) |
| 79 | { |
| 80 | fclose(info->file); |
| 81 | info->done = 1; |
| 82 | IPPrintf(info->socket, "226 Done\r\n"); |
| 83 | IPClose(socket); |
| 84 | return; |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | |
| 89 | static void FtpdServer(IPSocket *socket) |
| 90 | { |
| 91 | uint8 buf[600]; |
| 92 | int bytes; |
| 93 | int ip0, ip1, ip2, ip3, port0, port1; |
| 94 | IPSocket *socketOut; |
| 95 | FtpdInfo *info = (FtpdInfo*)socket->userPtr; |
| 96 | |
| 97 | if(socket == NULL) |
| 98 | return; |
| 99 | bytes = IPRead(socket, buf, sizeof(buf)-1); |
| 100 | buf[bytes] = 0; |
| 101 | //printf("(%s)\n", buf); |
| 102 | if(socket->userPtr == NULL) |
| 103 | { |
| 104 | info = (FtpdInfo*)malloc(sizeof(FtpdInfo)); |
| 105 | if(info == NULL) |
| 106 | return; |
| 107 | memset(info, 0, sizeof(FtpdInfo)); |
| 108 | socket->userPtr = info; |
| 109 | info->socket = socket; |
| 110 | socket->timeoutReset = 60; |
| 111 | IPPrintf(socket, "220 Connected to Plasma\r\n"); |
| 112 | } |
| 113 | else if(socket->userPtr == (void*)-1) |
| 114 | { |
| 115 | return; |
| 116 | } |
| 117 | else if(strstr((char*)buf, "USER")) |
| 118 | { |
| 119 | if(strstr((char*)buf, "PlasmaSend")) |
| 120 | info->canReceive = 1; |
| 121 | IPPrintf(socket, "331 Password?\r\n"); |
| 122 | } |
| 123 | else if(strstr((char*)buf, "PASS")) |
| 124 | { |
| 125 | IPPrintf(socket, "230 Logged in\r\n"); |
| 126 | } |
| 127 | else if(strstr((char*)buf, "PORT")) |
| 128 | { |
| 129 | sscanf((char*)buf + 5, "%d,%d,%d,%d,%d,%d", &ip0, &ip1, &ip2, &ip3, &port0, &port1); |
| 130 | info->ip = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; |
| 131 | info->port = (port0 << 8) | port1; |
| 132 | //printf("ip=0x%x port=%d\n", info->ip, info->port); |
| 133 | IPPrintf(socket, "200 OK\r\n"); |
| 134 | } |
| 135 | else if(strstr((char*)buf, "RETR") || strstr((char*)buf, "STOR")) |
| 136 | { |
| 137 | char *ptr = strstr((char*)buf, "\r"); |
| 138 | if(ptr) |
| 139 | *ptr = 0; |
| 140 | info->file = NULL; |
| 141 | info->bytes = 0; |
| 142 | info->done = 0; |
| 143 | if(strstr((char*)buf, "RETR")) |
| 144 | info->file = fopen((char*)buf + 5, "rb"); |
| 145 | else if(info->canReceive) |
| 146 | info->file = fopen((char*)buf + 5, "wb"); |
| 147 | if(info->file) |
| 148 | { |
| 149 | IPPrintf(socket, "150 File ready\r\n"); |
| 150 | if(strstr((char*)buf, "RETR")) |
| 151 | socketOut = IPOpen(IP_MODE_TCP, info->ip, info->port, FtpdSender); |
| 152 | else |
| 153 | socketOut = IPOpen(IP_MODE_TCP, info->ip, info->port, FtpdReceiver); |
| 154 | if(socketOut) |
| 155 | socketOut->userPtr = info; |
| 156 | } |
| 157 | else |
| 158 | { |
| 159 | IPPrintf(socket, "500 Error\r\n"); |
| 160 | } |
| 161 | } |
| 162 | else if(strstr((char*)buf, "QUIT")) |
| 163 | { |
| 164 | if(socket->userPtr) |
| 165 | free(socket->userPtr); |
| 166 | socket->userPtr = (void*)-1; |
| 167 | IPPrintf(socket, "221 Bye\r\n"); |
| 168 | IPClose(socket); |
| 169 | } |
| 170 | else if(bytes) |
| 171 | { |
| 172 | IPPrintf(socket, "500 Error\r\n"); |
| 173 | } |
| 174 | } |
| 175 | |
| 176 | |
| 177 | void FtpdInit(int UseFiles) |
| 178 | { |
| 179 | (void)UseFiles; |
| 180 | IPOpen(IP_MODE_TCP, 0, 21, FtpdServer); |
| 181 | } |
| 182 | |
| 183 | |
| 184 | //******************* FTP Client ************************ |
| 185 | |
| 186 | typedef struct { |
| 187 | uint32 ip, port; |
| 188 | char user[80], passwd[80], filename[80]; |
| 189 | uint8 *buf; |
| 190 | int size, bytes, send, state; |
| 191 | } FtpInfo; |
| 192 | |
| 193 | |
| 194 | static void FtpCallbackTransfer(IPSocket *socket) |
| 195 | { |
| 196 | int bytes, state = socket->state; |
| 197 | FtpInfo *info = (FtpInfo*)socket->userPtr; |
| 198 | |
| 199 | //printf("FtpCallbackTransfer\n"); |
| 200 | if(info == NULL) |
| 201 | return; |
| 202 | bytes = info->size - info->bytes; |
| 203 | if(info->send == 0) |
| 204 | bytes = IPRead(socket, info->buf + info->bytes, bytes); |
| 205 | else |
| 206 | bytes = IPWrite(socket, info->buf + info->bytes, bytes); |
| 207 | info->bytes += bytes; |
| 208 | if(info->bytes == info->size || (bytes == 0 && state > IP_TCP)) |
| 209 | { |
| 210 | socket->userFunc(info->buf, info->bytes); |
| 211 | free(info); |
| 212 | socket->userPtr = NULL; |
| 213 | IPClose(socket); |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | |
| 218 | static void FtpCallback(IPSocket *socket) |
| 219 | { |
| 220 | char buf[600]; |
| 221 | FtpInfo *info = (FtpInfo*)socket->userPtr; |
| 222 | int bytes, value; |
| 223 | |
| 224 | bytes = IPRead(socket, (uint8*)buf, sizeof(buf)-1); |
| 225 | if(bytes == 0) |
| 226 | return; |
| 227 | buf[bytes] = 0; |
| 228 | sscanf(buf, "%d", &value); |
| 229 | if(bytes > 2) |
| 230 | buf[bytes-2] = 0; |
| 231 | //printf("FtpCallback(%d:%s)\n", socket->userData, buf); |
| 232 | if(value / 100 != 2 && value / 100 != 3) |
| 233 | return; |
| 234 | buf[0] = 0; |
| 235 | switch(socket->userData) { |
| 236 | case 0: |
| 237 | sprintf(buf, "USER %s\r\n", info->user); |
| 238 | socket->userData = 1; |
| 239 | break; |
| 240 | case 1: |
| 241 | sprintf(buf, "PASS %s\r\n", info->passwd); |
| 242 | socket->userData = 2; |
| 243 | if(value == 331) |
| 244 | break; //possible fall-through |
| 245 | case 2: |
| 246 | sprintf(buf, "PORT %d,%d,%d,%d,%d,%d\r\n", |
| 247 | info->ip >> 24, (uint8)(info->ip >> 16), |
| 248 | (uint8)(info->ip >> 8), (uint8)info->ip, |
| 249 | (uint8)(info->port >> 8), (uint8)info->port); |
| 250 | socket->userData = 3; |
| 251 | break; |
| 252 | case 3: |
| 253 | if(info->send == 0) |
| 254 | sprintf(buf, "RETR %s\r\n", info->filename); |
| 255 | else |
| 256 | sprintf(buf, "STOR %s\r\n", info->filename); |
| 257 | socket->userData = 4; |
| 258 | break; |
| 259 | case 4: |
| 260 | sprintf(buf, "QUIT\r\n"); |
| 261 | socket->userData = 9; |
| 262 | break; |
| 263 | } |
| 264 | IPWrite(socket, (uint8*)buf, strlen(buf)); |
| 265 | IPWriteFlush(socket); |
| 266 | if(socket->userData == 9) |
| 267 | IPClose(socket); |
| 268 | } |
| 269 | |
| 270 | |
| 271 | IPSocket *FtpTransfer(uint32 ip, char *user, char *passwd, |
| 272 | char *filename, uint8 *buf, int size, |
| 273 | int send, void (*callback)(uint8 *data, int size)) |
| 274 | { |
| 275 | IPSocket *socket, *socketTransfer; |
| 276 | FtpInfo *info; |
| 277 | uint8 *ptr; |
| 278 | info = (FtpInfo*)malloc(sizeof(FtpInfo)); |
| 279 | if(info == NULL) |
| 280 | return NULL; |
| 281 | strncpy(info->user, user, 80); |
| 282 | strncpy(info->passwd, passwd, 80); |
| 283 | strncpy(info->filename, filename, 80); |
| 284 | info->buf = buf; |
| 285 | info->size = size; |
| 286 | info->send = send; |
| 287 | info->bytes = 0; |
| 288 | info->state = 0; |
| 289 | info->port = 2000; |
| 290 | socketTransfer = IPOpen(IP_MODE_TCP, 0, info->port, FtpCallbackTransfer); |
| 291 | socketTransfer->userPtr = info; |
| 292 | socketTransfer->userFunc = callback; |
| 293 | socket = IPOpen(IP_MODE_TCP, ip, 21, FtpCallback); |
| 294 | socket->userPtr = info; |
| 295 | socket->userFunc = callback; |
| 296 | ptr = socket->headerSend; |
| 297 | info->ip = IPAddressSelf(); |
| 298 | return socket; |
| 299 | } |
| 300 | |
| 301 | |
| 302 | //******************* TFTP Server ************************ |
| 303 | |
| 304 | |
| 305 | static void TftpdCallback(IPSocket *socket) |
| 306 | { |
| 307 | unsigned char buf[512+4]; |
| 308 | int bytes, blockNum; |
| 309 | FILE *file = (FILE*)socket->userPtr; |
| 310 | bytes = IPRead(socket, buf, sizeof(buf)); |
| 311 | //printf("TfptdCallback bytes=%d\n", bytes); |
| 312 | if(bytes < 4 || buf[0]) |
| 313 | return; |
| 314 | if(buf[1] == 1) //RRQ = Read Request |
| 315 | { |
| 316 | if(file) |
| 317 | fclose(file); |
| 318 | file = fopen((char*)buf+2, "rb"); |
| 319 | socket->userPtr = file; |
| 320 | if(file == NULL) |
| 321 | { |
| 322 | buf[0] = 0; |
| 323 | buf[1] = 5; //ERROR |
| 324 | buf[2] = 0; |
| 325 | buf[3] = 0; |
| 326 | buf[4] = 'X'; //Error string |
| 327 | buf[5] = 0; |
| 328 | IPWrite(socket, buf, 6); |
| 329 | return; |
| 330 | } |
| 331 | } |
| 332 | if(buf[1] == 1 || buf[1] == 4) //ACK |
| 333 | { |
| 334 | if(file == NULL) |
| 335 | return; |
| 336 | if(buf[1] == 1) |
| 337 | blockNum = 0; |
| 338 | else |
| 339 | blockNum = (buf[2] << 8) | buf[3]; |
| 340 | ++blockNum; |
| 341 | buf[0] = 0; |
| 342 | buf[1] = 3; //DATA |
| 343 | buf[2] = (uint8)(blockNum >> 8); |
| 344 | buf[3] = (uint8)blockNum; |
| 345 | fseek(file, (blockNum-1)*512, 0); |
| 346 | bytes = fread(buf+4, 1, 512, file); |
| 347 | IPWrite(socket, buf, bytes+4); |
| 348 | } |
| 349 | } |
| 350 | |
| 351 | |
| 352 | void TftpdInit(void) |
| 353 | { |
| 354 | IPSocket *socket; |
| 355 | socket = IPOpen(IP_MODE_UDP, 0, 69, TftpdCallback); |
| 356 | } |
| 357 | |
| 358 | |
| 359 | //******************* TFTP Client ************************ |
| 360 | |
| 361 | |
| 362 | static void TftpCallback(IPSocket *socket) |
| 363 | { |
| 364 | unsigned char buf[512+4]; |
| 365 | int bytes, blockNum, length; |
| 366 | |
| 367 | bytes = IPRead(socket, buf, sizeof(buf)); |
| 368 | if(bytes < 4 || buf[0]) |
| 369 | return; |
| 370 | blockNum = (buf[2] << 8) | buf[3]; |
| 371 | length = blockNum * 512 - 512 + bytes - 4; |
| 372 | //printf("TftpCallback(%d,%d)\n", buf[1], blockNum); |
| 373 | if(length > (int)socket->userData) |
| 374 | { |
| 375 | bytes -= length - (int)socket->userData; |
| 376 | length = (int)socket->userData; |
| 377 | } |
| 378 | if(buf[1] == 3) //DATA |
| 379 | { |
| 380 | memcpy((uint8*)socket->userPtr + blockNum * 512 - 512, buf+4, bytes-4); |
| 381 | buf[1] = 4; //ACK |
| 382 | IPWrite(socket, buf, 4); |
| 383 | if(bytes-4 < 512) |
| 384 | { |
| 385 | socket->userFunc(socket->userPtr, length); |
| 386 | IPClose(socket); |
| 387 | } |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | |
| 392 | IPSocket *TftpTransfer(uint32 ip, char *filename, uint8 *buffer, int size, |
| 393 | void (*callback)(uint8 *data, int bytes)) |
| 394 | { |
| 395 | IPSocket *socket; |
| 396 | uint8 buf[512+4]; |
| 397 | int bytes; |
| 398 | socket = IPOpen(IP_MODE_UDP, ip, 69, TftpCallback); |
| 399 | socket->userPtr = buffer; |
| 400 | socket->userData = size; |
| 401 | socket->userFunc = callback; |
| 402 | buf[0] = 0; |
| 403 | buf[1] = 1; //read |
| 404 | strcpy((char*)buf+2, filename); |
| 405 | bytes = strlen(filename); |
| 406 | strcpy((char*)buf+bytes+3, "octet"); |
| 407 | IPWrite(socket, buf, bytes+9); |
| 408 | return socket; |
| 409 | } |
| 410 | |
| 411 | |
| 412 | //******************* Telnet Server ************************ |
| 413 | |
| 414 | #define COMMAND_BUFFER_SIZE 80 |
| 415 | #define COMMAND_BUFFER_COUNT 10 |
| 416 | static char CommandHistory[400]; |
| 417 | static char *CommandPtr[COMMAND_BUFFER_COUNT]; |
| 418 | static int CommandIndex; |
| 419 | |
| 420 | typedef void (*ConsoleFunc)(IPSocket *socket, char *argv[]); |
| 421 | typedef struct { |
| 422 | char *name; |
| 423 | ConsoleFunc func; |
| 424 | } TelnetFunc_t; |
| 425 | static TelnetFunc_t *TelnetFuncList; |
| 426 | |
| 427 | |
| 428 | static void TelnetServer(IPSocket *socket) |
| 429 | { |
| 430 | uint8 buf[COMMAND_BUFFER_SIZE+4]; |
| 431 | char bufOut[32]; |
| 432 | int bytes, i, j, k, length, found; |
| 433 | char *ptr, *command = socket->userPtr; |
| 434 | char *argv[10]; |
| 435 | |
| 436 | if(socket->state > IP_TCP) |
| 437 | return; |
| 438 | for(;;) |
| 439 | { |
| 440 | bytes = IPRead(socket, buf, sizeof(buf)-1); |
| 441 | if(command == NULL) |
| 442 | { |
| 443 | socket->userPtr = command = (char*)malloc(COMMAND_BUFFER_SIZE); |
| 444 | if(command == NULL) |
| 445 | { |
| 446 | IPClose(socket); |
| 447 | return; |
| 448 | } |
| 449 | socket->timeoutReset = 300; |
| 450 | buf[0] = 255; //IAC |
| 451 | buf[1] = 251; //WILL |
| 452 | buf[2] = 3; //suppress go ahead |
| 453 | buf[3] = 255; //IAC |
| 454 | buf[4] = 251; //WILL |
| 455 | buf[5] = 1; //echo |
| 456 | strcpy((char*)buf+6, "Welcome to Plasma.\r\n-> "); |
| 457 | IPWrite(socket, buf, 6+23); |
| 458 | IPWriteFlush(socket); |
| 459 | command[0] = 0; |
| 460 | return; |
| 461 | } |
| 462 | if(bytes == 0) |
| 463 | return; |
| 464 | socket->dontFlush = 0; |
| 465 | buf[bytes] = 0; |
| 466 | length = (int)strlen(command); |
| 467 | for(j = 0; j < bytes; ++j) |
| 468 | { |
| 469 | if(buf[j] == 255) |
| 470 | return; |
| 471 | if(buf[j] == 8 || (buf[j] == 27 && buf[j+2] == 'D')) |
| 472 | { |
| 473 | if(buf[j] == 27) |
| 474 | j += 2; |
| 475 | if(length) |
| 476 | { |
| 477 | // Backspace |
| 478 | command[--length] = 0; |
| 479 | bufOut[0] = 8; |
| 480 | bufOut[1] = ' '; |
| 481 | bufOut[2] = 8; |
| 482 | IPWrite(socket, (uint8*)bufOut, 3); |
| 483 | } |
| 484 | } |
| 485 | else if(buf[j] == 27) |
| 486 | { |
| 487 | // Command History |
| 488 | if(buf[j+2] == 'A') |
| 489 | { |
| 490 | if(++CommandIndex > COMMAND_BUFFER_COUNT) |
| 491 | CommandIndex = COMMAND_BUFFER_COUNT; |
| 492 | } |
| 493 | else if(buf[j+2] == 'B') |
| 494 | { |
| 495 | if(--CommandIndex < 0) |
| 496 | CommandIndex = 0; |
| 497 | } |
| 498 | else |
| 499 | return; |
| 500 | bufOut[0] = 8; |
| 501 | bufOut[1] = ' '; |
| 502 | bufOut[2] = 8; |
| 503 | for(i = 0; i < length; ++i) |
| 504 | IPWrite(socket, (uint8*)bufOut, 3); |
| 505 | command[0] = 0; |
| 506 | if(CommandIndex && CommandPtr[CommandIndex-1]) |
| 507 | strncat(command, CommandPtr[CommandIndex-1], COMMAND_BUFFER_SIZE-1); |
| 508 | length = (int)strlen(command); |
| 509 | IPWrite(socket, (uint8*)command, length); |
| 510 | j += 2; |
| 511 | } |
| 512 | else |
| 513 | { |
| 514 | if(buf[j] == 0) |
| 515 | buf[j] = '\n'; //Linux support |
| 516 | if(length < COMMAND_BUFFER_SIZE-4 || (length < |
| 517 | COMMAND_BUFFER_SIZE-2 && (buf[j] == '\r' || buf[j] == '\n'))) |
| 518 | { |
| 519 | IPWrite(socket, buf+j, 1); |
| 520 | command[length] = buf[j]; |
| 521 | command[++length] = 0; |
| 522 | } |
| 523 | } |
| 524 | ptr = strstr(command, "\r\n"); |
| 525 | if(ptr) |
| 526 | { |
| 527 | // Save command in CommandHistory |
| 528 | ptr[0] = 0; |
| 529 | length = (int)strlen(command); |
| 530 | if(length == 0) |
| 531 | { |
| 532 | IPPrintf(socket, "-> "); |
| 533 | continue; |
| 534 | } |
| 535 | if(length < COMMAND_BUFFER_SIZE) |
| 536 | { |
| 537 | memmove(CommandHistory + length + 1, CommandHistory, |
| 538 | sizeof(CommandHistory) - length - 1); |
| 539 | strcpy(CommandHistory, command); |
| 540 | CommandHistory[sizeof(CommandHistory)-1] = 0; |
| 541 | for(i = COMMAND_BUFFER_COUNT-2; i >= 0; --i) |
| 542 | { |
| 543 | if(CommandPtr[i] == NULL || CommandPtr[i] + length + 1 >= |
| 544 | CommandHistory + sizeof(CommandHistory)) |
| 545 | CommandPtr[i+1] = NULL; |
| 546 | else |
| 547 | CommandPtr[i+1] = CommandPtr[i] + length + 1; |
| 548 | } |
| 549 | CommandPtr[0] = CommandHistory; |
| 550 | } |
| 551 | |
| 552 | //Start command |
| 553 | for(i = 0; i < 10; ++i) |
| 554 | argv[i] = ""; |
| 555 | i = 0; |
| 556 | argv[i++] = command; |
| 557 | for(ptr = command; *ptr && i < 10; ++ptr) |
| 558 | { |
| 559 | if(*ptr == ' ') |
| 560 | { |
| 561 | *ptr = 0; |
| 562 | argv[i++] = ptr + 1; |
| 563 | } |
| 564 | } |
| 565 | if(argv[0][0] == 0) |
| 566 | { |
| 567 | IPPrintf(socket, "-> "); |
| 568 | continue; |
| 569 | } |
| 570 | found = 0; |
| 571 | for(i = 0; TelnetFuncList[i].name; ++i) |
| 572 | { |
| 573 | if(strcmp(command, TelnetFuncList[i].name) == 0 && |
| 574 | TelnetFuncList[i].func) |
| 575 | { |
| 576 | found = 1; |
| 577 | for(k = 1; k < 10; ++k) |
| 578 | { |
| 579 | if(argv[k][0] == '>' && argv[k][1]) //stdout to file? |
| 580 | { |
| 581 | socket->fileOut = fopen(&argv[k][1], "a"); |
| 582 | argv[k] = ""; |
| 583 | } |
| 584 | if(argv[k][0] == '<' && argv[k][1]) //stdin from file? |
| 585 | { |
| 586 | socket->fileIn = fopen(&argv[k][1], "r"); |
| 587 | argv[k] = ""; |
| 588 | } |
| 589 | } |
| 590 | TelnetFuncList[i].func(socket, argv); |
| 591 | if(socket->fileOut) |
| 592 | { |
| 593 | fwrite("\r\n", 1, 2, socket->fileOut); |
| 594 | fclose(socket->fileOut); |
| 595 | } |
| 596 | socket->fileOut = NULL; |
| 597 | break; |
| 598 | } |
| 599 | } |
| 600 | #ifdef DLL_SETUP |
| 601 | if(found == 0) |
| 602 | { |
| 603 | strcpy((char*)buf, "/flash/bin/"); |
| 604 | strcat((char*)buf, argv[0]); |
| 605 | argv[0] = (char*)buf; |
| 606 | ConsoleRun(socket, argv); |
| 607 | } |
| 608 | #endif |
| 609 | if(socket->state > IP_TCP) |
| 610 | return; |
| 611 | command[0] = 0; |
| 612 | length = 0; |
| 613 | CommandIndex = 0; |
| 614 | if(socket->dontFlush == 0) |
| 615 | IPPrintf(socket, "\r\n-> "); |
| 616 | } //command entered |
| 617 | } //bytes |
| 618 | IPWriteFlush(socket); |
| 619 | } |
| 620 | } |
| 621 | |
| 622 | |
| 623 | void TelnetInit(TelnetFunc_t *funcList) |
| 624 | { |
| 625 | IPSocket *socket; |
| 626 | TelnetFuncList = funcList; |
| 627 | socket = IPOpen(IP_MODE_TCP, 0, 23, TelnetServer); |
| 628 | } |
| 629 | |
| 630 | |
| 631 | //******************* Console ************************ |
| 632 | |
| 633 | #define STORAGE_SIZE 1024*64 |
| 634 | static uint8 *myStorage; |
| 635 | static IPSocket *socketTelnet; |
| 636 | static char storageFilename[60]; |
| 637 | |
| 638 | |
| 639 | static void ConsoleHelp(IPSocket *socket, char *argv[]) |
| 640 | { |
| 641 | char buf[200]; |
| 642 | int i; |
| 643 | (void)argv; |
| 644 | strcpy(buf, "Commands: "); |
| 645 | for(i = 0; TelnetFuncList[i].name; ++i) |
| 646 | { |
| 647 | if(TelnetFuncList[i].func) |
| 648 | { |
| 649 | if(i) |
| 650 | strcat(buf, ", "); |
| 651 | strcat(buf, TelnetFuncList[i].name); |
| 652 | } |
| 653 | } |
| 654 | IPPrintf(socket, buf); |
| 655 | } |
| 656 | |
| 657 | |
| 658 | static void ConsoleExit(IPSocket *socket, char *argv[]) |
| 659 | { |
| 660 | free(argv[0]); |
| 661 | socket->userPtr = NULL; |
| 662 | IPClose(socket); |
| 663 | } |
| 664 | |
| 665 | |
| 666 | static void ConsoleCat(IPSocket *socket, char *argv[]) |
| 667 | { |
| 668 | FILE *file; |
| 669 | uint8 buf[200]; |
| 670 | int bytes; |
| 671 | |
| 672 | file = fopen(argv[1], "r"); |
| 673 | if(file == NULL) |
| 674 | return; |
| 675 | for(;;) |
| 676 | { |
| 677 | bytes = fread(buf, 1, sizeof(buf), file); |
| 678 | if(bytes == 0) |
| 679 | break; |
| 680 | IPWrite(socket, buf, bytes); |
| 681 | } |
| 682 | fclose(file); |
| 683 | } |
| 684 | |
| 685 | |
| 686 | static void ConsoleCp(IPSocket *socket, char *argv[]) |
| 687 | { |
| 688 | FILE *fileIn, *fileOut; |
| 689 | uint8 buf[200]; |
| 690 | int bytes; |
| 691 | (void)socket; |
| 692 | |
| 693 | fileIn = fopen(argv[1], "r"); |
| 694 | if(fileIn == NULL) |
| 695 | return; |
| 696 | fileOut = fopen(argv[2], "w"); |
| 697 | if(fileOut) |
| 698 | { |
| 699 | for(;;) |
| 700 | { |
| 701 | bytes = fread(buf, 1, sizeof(buf), fileIn); |
| 702 | if(bytes == 0) |
| 703 | break; |
| 704 | fwrite(buf, 1, bytes, fileOut); |
| 705 | } |
| 706 | fclose(fileOut); |
| 707 | } |
| 708 | fclose(fileIn); |
| 709 | } |
| 710 | |
| 711 | |
| 712 | static void ConsoleRm(IPSocket *socket, char *argv[]) |
| 713 | { |
| 714 | (void)socket; |
| 715 | OS_fdelete(argv[1]); |
| 716 | } |
| 717 | |
| 718 | |
| 719 | static void ConsoleMkdir(IPSocket *socket, char *argv[]) |
| 720 | { |
| 721 | (void)socket; |
| 722 | OS_fmkdir(argv[1]); |
| 723 | } |
| 724 | |
| 725 | |
| 726 | static void ConsoleLs(IPSocket *socket, char *argv[]) |
| 727 | { |
| 728 | FILE *file; |
| 729 | char buf[200], buf2[80]; |
| 730 | int bytes, width; |
| 731 | |
| 732 | file = fopen(argv[1], "r"); |
| 733 | if(file == NULL) |
| 734 | return; |
| 735 | width = 0; |
| 736 | for(;;) |
| 737 | { |
| 738 | bytes = OS_fdir(file, buf); |
| 739 | if(bytes) |
| 740 | break; |
| 741 | if(buf[0] == 255) |
| 742 | continue; |
| 743 | bytes = OS_flength(buf); |
| 744 | sprintf(buf2, "%s:%d ", buf, bytes); |
| 745 | bytes = strlen(buf2); |
| 746 | bytes -= bytes % 20; |
| 747 | buf2[bytes] = 0; |
| 748 | width += bytes; |
| 749 | if(width == 80) |
| 750 | --bytes; |
| 751 | if(width > 80) |
| 752 | { |
| 753 | IPPrintf(socket, "\n"); |
| 754 | width = bytes; |
| 755 | } |
| 756 | IPPrintf(socket, "%s", buf2); |
| 757 | } |
| 758 | fclose(file); |
| 759 | } |
| 760 | |
| 761 | |
| 762 | #ifdef INCLUDE_FLASH |
| 763 | static void ConsoleFlashErase(IPSocket *socket, char *argv[]) |
| 764 | { |
| 765 | int bytes; |
| 766 | (void)argv; |
| 767 | IPPrintf(socket, "\r\nErasing"); |
| 768 | for(bytes = 1024*128; bytes < 1024*1024*16; bytes += 1024*128) |
| 769 | { |
| 770 | IPPrintf(socket, "."); |
| 771 | FlashErase(bytes); |
| 772 | } |
| 773 | IPPrintf(socket, "\r\nMust Reboot\r\n"); |
| 774 | OS_ThreadSleep(OS_WAIT_FOREVER); |
| 775 | } |
| 776 | #endif |
| 777 | |
| 778 | |
| 779 | static void ConsoleMath(IPSocket *socket, char *argv[]) |
| 780 | { |
| 781 | int v1, v2, ch; |
| 782 | if(argv[3][0] == 0) |
| 783 | { |
| 784 | IPPrintf(socket, "Usage: math <number> <operator> <value>\r\n"); |
| 785 | return; |
| 786 | } |
| 787 | v1 = atoi(argv[1]); |
| 788 | ch = argv[2][0]; |
| 789 | v2 = atoi(argv[3]); |
| 790 | if(ch == '+') |
| 791 | v1 += v2; |
| 792 | else if(ch == '-') |
| 793 | v1 -= v2; |
| 794 | else if(ch == '*') |
| 795 | v1 *= v2; |
| 796 | else if(ch == '/') |
| 797 | { |
| 798 | if(v2 != 0) |
| 799 | v1 /= v2; |
| 800 | } |
| 801 | IPPrintf(socket, "%d", v1); |
| 802 | } |
| 803 | |
| 804 | |
| 805 | static void PingCallback(IPSocket *socket) |
| 806 | { |
| 807 | IPSocket *socket2 = socket->userPtr; |
| 808 | IPClose(socket); |
| 809 | if(socket2) |
| 810 | IPPrintf(socket2, "Ping Reply"); |
| 811 | else |
| 812 | printf("Ping Reply\n"); |
| 813 | } |
| 814 | |
| 815 | |
| 816 | static void DnsResultCallback(IPSocket *socket, uint32 ip, void *arg) |
| 817 | { |
| 818 | char buf[COMMAND_BUFFER_SIZE]; |
| 819 | IPSocket *socketTelnet = arg; |
| 820 | IPSocket *socketPing; |
| 821 | (void)socket; |
| 822 | |
| 823 | sprintf(buf, "ip=%d.%d.%d.%d\r\n", |
| 824 | (uint8)(ip >> 24), (uint8)(ip >> 16), (uint8)(ip >> 8), (uint8)ip); |
| 825 | IPPrintf(socketTelnet, buf); |
| 826 | socketPing = IPOpen(IP_MODE_PING, ip, 0, PingCallback); |
| 827 | socketPing->userPtr = socketTelnet; |
| 828 | buf[0] = 'A'; |
| 829 | IPWrite(socketPing, (uint8*)buf, 1); |
| 830 | } |
| 831 | |
| 832 | |
| 833 | static void ConsolePing(IPSocket *socket, char *argv[]) |
| 834 | { |
| 835 | int ip0, ip1, ip2, ip3; |
| 836 | |
| 837 | if('0' <= argv[1][0] && argv[1][0] <= '9') |
| 838 | { |
| 839 | sscanf(argv[1], "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); |
| 840 | ip0 = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; |
| 841 | DnsResultCallback(socket, ip0, socket); |
| 842 | } |
| 843 | else |
| 844 | { |
| 845 | IPResolve(argv[1], DnsResultCallback, socket); |
| 846 | IPPrintf(socket, "Sent DNS request"); |
| 847 | } |
| 848 | } |
| 849 | |
| 850 | |
| 851 | static void ConsoleTransferDone(uint8 *data, int length) |
| 852 | { |
| 853 | FILE *file; |
| 854 | IPPrintf(socketTelnet, "Transfer Done"); |
| 855 | file = fopen(storageFilename, "w"); |
| 856 | if(file) |
| 857 | { |
| 858 | fwrite(data, 1, length, file); |
| 859 | fclose(file); |
| 860 | } |
| 861 | if(myStorage) |
| 862 | free(myStorage); |
| 863 | myStorage = NULL; |
| 864 | } |
| 865 | |
| 866 | |
| 867 | static void ConsoleFtp(IPSocket *socket, char *argv[]) |
| 868 | { |
| 869 | int ip0, ip1, ip2, ip3; |
| 870 | if(argv[1][0] == 0) |
| 871 | { |
| 872 | IPPrintf(socket, "ftp #.#.#.# User Password File"); |
| 873 | return; |
| 874 | } |
| 875 | sscanf(argv[1], "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); |
| 876 | ip0 = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; |
| 877 | socketTelnet = socket; |
| 878 | if(myStorage == NULL) |
| 879 | myStorage = (uint8*)malloc(STORAGE_SIZE); |
| 880 | if(myStorage == NULL) |
| 881 | return; |
| 882 | strcpy(storageFilename, argv[4]); |
| 883 | FtpTransfer(ip0, argv[2], argv[3], argv[4], myStorage, STORAGE_SIZE-1, |
| 884 | 0, ConsoleTransferDone); |
| 885 | } |
| 886 | |
| 887 | |
| 888 | static void ConsoleTftp(IPSocket *socket, char *argv[]) |
| 889 | { |
| 890 | int ip0, ip1, ip2, ip3; |
| 891 | if(argv[1][0] == 0) |
| 892 | { |
| 893 | IPPrintf(socket, "tftp #.#.#.# File"); |
| 894 | return; |
| 895 | } |
| 896 | sscanf(argv[1], "%d.%d.%d.%d", &ip0, &ip1, &ip2, &ip3); |
| 897 | ip0 = (ip0 << 24) | (ip1 << 16) | (ip2 << 8) | ip3; |
| 898 | socketTelnet = socket; |
| 899 | if(myStorage == NULL) |
| 900 | myStorage = (uint8*)malloc(STORAGE_SIZE); |
| 901 | if(myStorage == NULL) |
| 902 | return; |
| 903 | strcpy(storageFilename, argv[2]); |
| 904 | TftpTransfer(ip0, argv[2], myStorage, STORAGE_SIZE-1, ConsoleTransferDone); |
| 905 | } |
| 906 | |
| 907 | |
| 908 | static void ConsoleMkfile(IPSocket *socket, char *argv[]) |
| 909 | { |
| 910 | OS_FILE *file; |
| 911 | (void)argv; |
| 912 | file = fopen("myfile.txt", "w"); |
| 913 | fwrite("Hello World!", 1, 12, file); |
| 914 | fclose(file); |
| 915 | IPPrintf(socket, "Created myfile.txt"); |
| 916 | } |
| 917 | |
| 918 | |
| 919 | static void ConsoleUptime(IPSocket *socket, char *argv[]) |
| 920 | { |
| 921 | int days, hours, minutes, seconds; |
| 922 | (void)argv; |
| 923 | //ticks per sec = 25E6/2^18 = 95.36743 -> 10.48576 ms/tick |
| 924 | seconds = OS_ThreadTime() / 95; |
| 925 | minutes = seconds / 60 % 60; |
| 926 | hours = seconds / 3600 % 24; |
| 927 | days = seconds / 3600 / 24; |
| 928 | seconds %= 60; |
| 929 | IPPrintf(socket, "%d days %2d:%2d:%2d\n", days, hours, minutes, seconds); |
| 930 | } |
| 931 | |
| 932 | |
| 933 | static void ConsoleDump(IPSocket *socket, char *argv[]) |
| 934 | { |
| 935 | FILE *fileIn; |
| 936 | uint8 buf[16]; |
| 937 | int bytes, i, j; |
| 938 | |
| 939 | fileIn = fopen(argv[1], "r"); |
| 940 | if(fileIn == NULL) |
| 941 | return; |
| 942 | for(j = 0; j < 1024*1024*16; j += 16) |
| 943 | { |
| 944 | bytes = fread(buf, 1, 16, fileIn); |
| 945 | if(bytes == 0) |
| 946 | break; |
| 947 | IPPrintf(socket, "%8x ", j); |
| 948 | for(i = 0; i < bytes; ++i) |
| 949 | IPPrintf(socket, "%2x ", buf[i]); |
| 950 | for( ; i < 16; ++i) |
| 951 | IPPrintf(socket, " "); |
| 952 | for(i = 0; i < bytes; ++i) |
| 953 | { |
| 954 | if(isprint(buf[i])) |
| 955 | IPPrintf(socket, "%c", buf[i]); |
| 956 | else |
| 957 | IPPrintf(socket, "."); |
| 958 | } |
| 959 | IPPrintf(socket, "\n"); |
| 960 | } |
| 961 | fclose(fileIn); |
| 962 | } |
| 963 | |
| 964 | |
| 965 | static void ConsoleGrep(IPSocket *socket, char *argv[]) |
| 966 | { |
| 967 | FILE *fileIn; |
| 968 | char buf[200]; |
| 969 | int bytes; |
| 970 | char *ptr, *ptrEnd; |
| 971 | |
| 972 | if(argv[1][0] == 0 || argv[2][0] == 0) |
| 973 | { |
| 974 | IPPrintf(socket, "Usage: grep pattern file\n"); |
| 975 | return; |
| 976 | } |
| 977 | fileIn = fopen(argv[2], "r"); |
| 978 | if(fileIn == NULL) |
| 979 | return; |
| 980 | bytes = 0; |
| 981 | for(;;) |
| 982 | { |
| 983 | bytes += fread(buf + bytes, 1, sizeof(buf) - bytes - 1, fileIn); |
| 984 | if(bytes == 0) |
| 985 | break; |
| 986 | buf[bytes] = 0; |
| 987 | ptrEnd = strstr(buf, "\r"); |
| 988 | if(ptrEnd == NULL) |
| 989 | ptrEnd = strstr(buf, "\n"); |
| 990 | if(ptrEnd) |
| 991 | { |
| 992 | *ptrEnd = 0; |
| 993 | if(*++ptrEnd == '\n') |
| 994 | ++ptrEnd; |
| 995 | } |
| 996 | ptr = strstr(buf, argv[1]); |
| 997 | if(ptr) |
| 998 | IPPrintf(socket, "%s\n", buf); |
| 999 | if(ptrEnd) |
| 1000 | { |
| 1001 | bytes = strlen(ptrEnd); |
| 1002 | memcpy(buf, ptrEnd, bytes); |
| 1003 | } |
| 1004 | else |
| 1005 | { |
| 1006 | bytes = 0; |
| 1007 | } |
| 1008 | } |
| 1009 | fclose(fileIn); |
| 1010 | } |
| 1011 | |
| 1012 | |
| 1013 | #ifdef DLL_SETUP |
| 1014 | #include "dll.h" |
| 1015 | |
| 1016 | static void ConsoleRun(IPSocket *socket, char *argv[]) |
| 1017 | { |
| 1018 | FILE *file; |
| 1019 | int bytes, i; |
| 1020 | uint8 code[128]; |
| 1021 | DllFunc funcPtr; |
| 1022 | char *command, *ptr; |
| 1023 | |
| 1024 | if(strcmp(argv[0], "run") == 0) |
| 1025 | ++argv; |
| 1026 | file = fopen(argv[0], "r"); |
| 1027 | if(file == NULL) |
| 1028 | { |
| 1029 | IPPrintf(socket, "Can't find %s", argv[0]); |
| 1030 | return; |
| 1031 | } |
| 1032 | |
| 1033 | bytes = fread(code, 1, sizeof(code), file); //load first 128 bytes |
| 1034 | if(code[0] >= ' ') |
| 1035 | { |
| 1036 | socket->fileIn = file; //script file |
| 1037 | fseek(file, 0, 0); |
| 1038 | return; |
| 1039 | } |
| 1040 | |
| 1041 | funcPtr = (DllFunc)code; |
| 1042 | ptr = funcPtr(NULL); //determine load address |
| 1043 | |
| 1044 | memcpy(ptr, code, bytes); //copy to correct address |
| 1045 | bytes += fread(ptr + bytes, 1, 1024*1024*8, file); |
| 1046 | fclose(file); |
| 1047 | printf("address=0x%x bytes=%d\n", (int)ptr, bytes); |
| 1048 | funcPtr = (DllFunc)ptr; |
| 1049 | funcPtr = (DllFunc)funcPtr(DllFuncList); //initialize DLL, find Start() |
| 1050 | |
| 1051 | //Register new command |
| 1052 | command = argv[0]; |
| 1053 | for(;;) |
| 1054 | { |
| 1055 | ptr = strstr(command, "/"); |
| 1056 | if(ptr == NULL) |
| 1057 | break; |
| 1058 | command = ptr + 1; |
| 1059 | } |
| 1060 | for(i = 0; TelnetFuncList[i].name; ++i) |
| 1061 | { |
| 1062 | if(TelnetFuncList[i].name[0] == 0 || |
| 1063 | strcmp(TelnetFuncList[i].name, command) == 0) |
| 1064 | { |
| 1065 | TelnetFuncList[i].name = (char*)malloc(40); |
| 1066 | strcpy(TelnetFuncList[i].name, command); |
| 1067 | TelnetFuncList[i].func = (ConsoleFunc)funcPtr; |
| 1068 | break; |
| 1069 | } |
| 1070 | } |
| 1071 | |
| 1072 | socket->userFunc = socket->funcPtr; |
| 1073 | funcPtr(socket, argv); |
| 1074 | } |
| 1075 | |
| 1076 | |
| 1077 | typedef struct NameValue_t { |
| 1078 | struct NameValue_t *next; |
| 1079 | void *value; |
| 1080 | char name[1]; |
| 1081 | } NameValue_t; |
| 1082 | |
| 1083 | //Find the value associated with the name |
| 1084 | void *IPNameValue(const char *name, void *value) |
| 1085 | { |
| 1086 | static NameValue_t *head; |
| 1087 | NameValue_t *node; |
| 1088 | for(node = head; node; node = node->next) |
| 1089 | { |
| 1090 | if(strcmp(node->name, name) == 0) |
| 1091 | break; |
| 1092 | } |
| 1093 | if(node == NULL) |
| 1094 | { |
| 1095 | node = (NameValue_t*)malloc(sizeof(NameValue_t) + (int)strlen(name)); |
| 1096 | if(node == NULL) |
| 1097 | return NULL; |
| 1098 | strcpy(node->name, name); |
| 1099 | node->value = value; |
| 1100 | node->next = head; |
| 1101 | head = node; |
| 1102 | } |
| 1103 | if(value) |
| 1104 | node->value = value; |
| 1105 | return node->value; |
| 1106 | } |
| 1107 | #endif |
| 1108 | |
| 1109 | |
| 1110 | #ifdef EDIT_FILE |
| 1111 | extern void EditFile(IPSocket *socket, char *argv[]); |
| 1112 | #endif |
| 1113 | |
| 1114 | static TelnetFunc_t MyFuncs[] = { |
| 1115 | {"cat", ConsoleCat}, |
| 1116 | {"cp", ConsoleCp}, |
| 1117 | {"dump", ConsoleDump}, |
| 1118 | {"exit", ConsoleExit}, |
| 1119 | #ifdef INCLUDE_FLASH |
| 1120 | {"flashErase", ConsoleFlashErase}, |
| 1121 | #endif |
| 1122 | {"ftp", ConsoleFtp}, |
| 1123 | {"grep", ConsoleGrep}, |
| 1124 | {"help", ConsoleHelp}, |
| 1125 | {"ls", ConsoleLs}, |
| 1126 | {"math", ConsoleMath}, |
| 1127 | {"mkdir", ConsoleMkdir}, |
| 1128 | {"mkfile", ConsoleMkfile}, |
| 1129 | {"ping", ConsolePing}, |
| 1130 | {"rm", ConsoleRm}, |
| 1131 | {"tftp", ConsoleTftp}, |
| 1132 | {"uptime", ConsoleUptime}, |
| 1133 | #ifdef DLL_SETUP |
| 1134 | {"run", ConsoleRun}, |
| 1135 | #endif |
| 1136 | #ifdef EDIT_FILE |
| 1137 | {"edit", EditFile}, |
| 1138 | #endif |
| 1139 | {"", NULL}, |
| 1140 | {"", NULL}, |
| 1141 | {"", NULL}, |
| 1142 | {"", NULL}, |
| 1143 | {"", NULL}, |
| 1144 | {"", NULL}, |
| 1145 | {"", NULL}, |
| 1146 | {"", NULL}, |
| 1147 | {"", NULL}, |
| 1148 | {"", NULL}, |
| 1149 | {"", NULL}, |
| 1150 | {NULL, NULL} |
| 1151 | }; |
| 1152 | |
| 1153 | |
| 1154 | void ConsoleInit(void) |
| 1155 | { |
| 1156 | FtpdInit(1); |
| 1157 | TftpdInit(); |
| 1158 | TelnetInit(MyFuncs); |
| 1159 | } |
plasma/kernel/rtos.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma Real Time Operating System |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 12/17/05 |
| 5 | * FILENAME: rtos.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma Real Time Operating System |
| 11 | * Fully pre-emptive RTOS with support for: |
| 12 | * Heaps, Threads, Semaphores, Mutexes, Message Queues, and Timers. |
| 13 | * This file tries to be hardware independent except for calls to: |
| 14 | * MemoryRead() and MemoryWrite() for interrupts. |
| 15 | * Partial support for multiple CPUs using symmetric multiprocessing. |
| 16 | *--------------------------------------------------------------------*/ |
| 17 | #include "plasma.h" |
| 18 | #include "rtos.h" |
| 19 | |
| 20 | #define HEAP_MAGIC 0x1234abcd |
| 21 | #define THREAD_MAGIC 0x4321abcd |
| 22 | #define SEM_RESERVED_COUNT 2 |
| 23 | #define INFO_COUNT 4 |
| 24 | #define HEAP_COUNT 8 |
| 25 | |
| 26 | |
| 27 | /*************** Structures ***************/ |
| 28 | #ifdef WIN32 |
| 29 | #define setjmp _setjmp |
| 30 | //x86 registers |
| 31 | typedef struct jmp_buf2 { |
| 32 | uint32 Ebp, Ebx, Edi, Esi, sp, pc, extra[10]; |
| 33 | } jmp_buf2; |
| 34 | #elif defined(ARM_CPU) |
| 35 | //ARM registers |
| 36 | typedef struct jmp_buf2 { |
| 37 | uint32 r[13], sp, lr, pc, cpsr, extra[5]; |
| 38 | } jmp_buf2; |
| 39 | #else |
| 40 | //Plasma registers |
| 41 | typedef struct jmp_buf2 { |
| 42 | uint32 s[9], gp, sp, pc; |
| 43 | } jmp_buf2; |
| 44 | #endif |
| 45 | |
| 46 | typedef struct HeapNode_s { |
| 47 | struct HeapNode_s *next; |
| 48 | int size; |
| 49 | } HeapNode_t; |
| 50 | |
| 51 | struct OS_Heap_s { |
| 52 | uint32 magic; |
| 53 | const char *name; |
| 54 | OS_Semaphore_t *semaphore; |
| 55 | HeapNode_t *available; |
| 56 | HeapNode_t base; |
| 57 | struct OS_Heap_s *alternate; |
| 58 | }; |
| 59 | //typedef struct OS_Heap_s OS_Heap_t; |
| 60 | |
| 61 | typedef enum { |
| 62 | THREAD_PEND = 0, //Thread in semaphore's linked list |
| 63 | THREAD_READY = 1, //Thread in ThreadHead linked list |
| 64 | THREAD_RUNNING = 2 //Thread == ThreadCurrent[cpu] |
| 65 | } OS_ThreadState_e; |
| 66 | |
| 67 | struct OS_Thread_s { |
| 68 | const char *name; //Name of thread |
| 69 | OS_ThreadState_e state; //Pending, ready, or running |
| 70 | int cpuIndex; //Which CPU is running the thread |
| 71 | int cpuLock; //Lock the thread to a specific CPU |
| 72 | jmp_buf env; //Registers saved during context swap |
| 73 | OS_FuncPtr_t funcPtr; //First function called |
| 74 | void *arg; //Argument to first function called |
| 75 | uint32 priority; //Priority of thread (0=low, 255=high) |
| 76 | uint32 ticksTimeout; //Tick value when semaphore pend times out |
| 77 | void *info[INFO_COUNT]; //User storage |
| 78 | OS_Semaphore_t *semaphorePending; //Semaphore thread is blocked on |
| 79 | int returnCode; //Return value from semaphore pend |
| 80 | uint32 processId; //Process ID if using MMU |
| 81 | OS_Heap_t *heap; //Heap used if no heap specified |
| 82 | struct OS_Thread_s *next; //Linked list of threads by priority |
| 83 | struct OS_Thread_s *prev; |
| 84 | struct OS_Thread_s *nextTimeout; //Linked list of threads by timeout |
| 85 | struct OS_Thread_s *prevTimeout; |
| 86 | uint32 magic[1]; //Bottom of stack to detect stack overflow |
| 87 | }; |
| 88 | //typedef struct OS_Thread_s OS_Thread_t; |
| 89 | |
| 90 | struct OS_Semaphore_s { |
| 91 | const char *name; |
| 92 | struct OS_Thread_s *threadHead; //threads pending on semaphore |
| 93 | int count; |
| 94 | }; |
| 95 | //typedef struct OS_Semaphore_s OS_Semaphore_t; |
| 96 | |
| 97 | struct OS_Mutex_s { |
| 98 | OS_Semaphore_t *semaphore; |
| 99 | OS_Thread_t *thread; |
| 100 | int count; |
| 101 | }; |
| 102 | //typedef struct OS_Mutex_s OS_Mutex_t; |
| 103 | |
| 104 | struct OS_MQueue_s { |
| 105 | const char *name; |
| 106 | OS_Semaphore_t *semaphore; |
| 107 | int count, size, used, read, write; |
| 108 | }; |
| 109 | //typedef struct OS_MQueue_s OS_MQueue_t; |
| 110 | |
| 111 | struct OS_Timer_s { |
| 112 | const char *name; |
| 113 | struct OS_Timer_s *next, *prev; |
| 114 | uint32 ticksTimeout; |
| 115 | uint32 ticksRestart; |
| 116 | int active; |
| 117 | OS_TimerFuncPtr_t callback; |
| 118 | OS_MQueue_t *mqueue; |
| 119 | uint32 info; |
| 120 | }; |
| 121 | //typedef struct OS_Timer_s OS_Timer_t; |
| 122 | |
| 123 | |
| 124 | /*************** Globals ******************/ |
| 125 | static OS_Heap_t *HeapArray[HEAP_COUNT]; |
| 126 | static int InterruptInside[OS_CPU_COUNT]; |
| 127 | static int ThreadNeedReschedule[OS_CPU_COUNT]; |
| 128 | static OS_Thread_t *ThreadCurrent[OS_CPU_COUNT]; //Currently running thread(s) |
| 129 | static OS_Thread_t *ThreadHead; //Linked list of threads sorted by priority |
| 130 | static OS_Thread_t *TimeoutHead; //Linked list of threads sorted by timeout |
| 131 | static int ThreadSwapEnabled; |
| 132 | static uint32 ThreadTime; |
| 133 | static void *NeedToFree; |
| 134 | static OS_Semaphore_t SemaphoreReserved[SEM_RESERVED_COUNT]; |
| 135 | static OS_Semaphore_t *SemaphoreSleep; |
| 136 | static OS_Semaphore_t *SemaphoreRelease; |
| 137 | static OS_Semaphore_t *SemaphoreLock; |
| 138 | static OS_Semaphore_t *SemaphoreTimer; |
| 139 | static OS_Timer_t *TimerHead; //Linked list of timers sorted by timeout |
| 140 | static OS_FuncPtr_t Isr[32]; |
| 141 | |
| 142 | |
| 143 | /***************** Heap *******************/ |
| 144 | /******************************************/ |
| 145 | OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size) |
| 146 | { |
| 147 | OS_Heap_t *heap; |
| 148 | |
| 149 | assert(((uint32)memory & 3) == 0); |
| 150 | heap = (OS_Heap_t*)memory; |
| 151 | heap->magic = HEAP_MAGIC; |
| 152 | heap->name = name; |
| 153 | heap->semaphore = OS_SemaphoreCreate(name, 1); |
| 154 | heap->available = (HeapNode_t*)(heap + 1); |
| 155 | heap->available->next = &heap->base; |
| 156 | heap->available->size = (size - sizeof(OS_Heap_t)) / sizeof(HeapNode_t); |
| 157 | heap->base.next = heap->available; |
| 158 | heap->base.size = 0; |
| 159 | return heap; |
| 160 | } |
| 161 | |
| 162 | |
| 163 | /******************************************/ |
| 164 | void OS_HeapDestroy(OS_Heap_t *heap) |
| 165 | { |
| 166 | OS_SemaphoreDelete(heap->semaphore); |
| 167 | } |
| 168 | |
| 169 | |
| 170 | /******************************************/ |
| 171 | //Modified from K&R |
| 172 | void *OS_HeapMalloc(OS_Heap_t *heap, int bytes) |
| 173 | { |
| 174 | HeapNode_t *node, *prevp; |
| 175 | int nunits; |
| 176 | |
| 177 | if(heap == NULL && OS_ThreadSelf()) |
| 178 | heap = OS_ThreadSelf()->heap; |
| 179 | if((uint32)heap < HEAP_COUNT) |
| 180 | heap = HeapArray[(int)heap]; |
| 181 | nunits = (bytes + sizeof(HeapNode_t) - 1) / sizeof(HeapNode_t) + 1; |
| 182 | OS_SemaphorePend(heap->semaphore, OS_WAIT_FOREVER); |
| 183 | prevp = heap->available; |
| 184 | for(node = prevp->next; ; prevp = node, node = node->next) |
| 185 | { |
| 186 | if(node->size >= nunits) //Big enough? |
| 187 | { |
| 188 | if(node->size == nunits) //Exactly |
| 189 | prevp->next = node->next; |
| 190 | else |
| 191 | { //Allocate tail end |
| 192 | node->size -= nunits; |
| 193 | node += node->size; |
| 194 | node->size = nunits; |
| 195 | } |
| 196 | heap->available = prevp; |
| 197 | node->next = (HeapNode_t*)heap; |
| 198 | OS_SemaphorePost(heap->semaphore); |
| 199 | return (void*)(node + 1); |
| 200 | } |
| 201 | if(node == heap->available) //Wrapped around free list |
| 202 | { |
| 203 | OS_SemaphorePost(heap->semaphore); |
| 204 | if(heap->alternate) |
| 205 | return OS_HeapMalloc(heap->alternate, bytes); |
| 206 | return NULL; |
| 207 | } |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | |
| 212 | /******************************************/ |
| 213 | //Modified from K&R |
| 214 | void OS_HeapFree(void *block) |
| 215 | { |
| 216 | OS_Heap_t *heap; |
| 217 | HeapNode_t *bp, *node; |
| 218 | |
| 219 | assert(block); |
| 220 | bp = (HeapNode_t*)block - 1; //point to block header |
| 221 | heap = (OS_Heap_t*)bp->next; |
| 222 | assert(heap->magic == HEAP_MAGIC); |
| 223 | if(heap->magic != HEAP_MAGIC) |
| 224 | return; |
| 225 | OS_SemaphorePend(heap->semaphore, OS_WAIT_FOREVER); |
| 226 | for(node = heap->available; !(node < bp && bp < node->next); node = node->next) |
| 227 | { |
| 228 | if(node >= node->next && (bp > node || bp < node->next)) |
| 229 | break; //freed block at start or end of area |
| 230 | } |
| 231 | |
| 232 | if(bp + bp->size == node->next) //join to upper |
| 233 | { |
| 234 | bp->size += node->next->size; |
| 235 | bp->next = node->next->next; |
| 236 | } |
| 237 | else |
| 238 | { |
| 239 | bp->next = node->next; |
| 240 | } |
| 241 | |
| 242 | if(node + node->size == bp) //join to lower |
| 243 | { |
| 244 | node->size += bp->size; |
| 245 | node->next = bp->next; |
| 246 | } |
| 247 | else |
| 248 | node->next = bp; |
| 249 | heap->available = node; |
| 250 | OS_SemaphorePost(heap->semaphore); |
| 251 | } |
| 252 | |
| 253 | |
| 254 | /******************************************/ |
| 255 | void OS_HeapAlternate(OS_Heap_t *heap, OS_Heap_t *alternate) |
| 256 | { |
| 257 | heap->alternate = alternate; |
| 258 | } |
| 259 | |
| 260 | |
| 261 | /******************************************/ |
| 262 | void OS_HeapRegister(void *index, OS_Heap_t *heap) |
| 263 | { |
| 264 | if((uint32)index < HEAP_COUNT) |
| 265 | HeapArray[(int)index] = heap; |
| 266 | } |
| 267 | |
| 268 | |
| 269 | |
| 270 | /***************** Thread *****************/ |
| 271 | /******************************************/ |
| 272 | //Linked list of threads sorted by priority |
| 273 | //The listed list is either ThreadHead (ready to run threads not including |
| 274 | //the currently running thread) or a list of threads waiting on a semaphore. |
| 275 | //Must be called with interrupts disabled |
| 276 | static void OS_ThreadPriorityInsert(OS_Thread_t **head, OS_Thread_t *thread) |
| 277 | { |
| 278 | OS_Thread_t *node, *prev; |
| 279 | |
| 280 | prev = NULL; |
| 281 | for(node = *head; node; node = node->next) |
| 282 | { |
| 283 | if(node->priority < thread->priority) |
| 284 | break; |
| 285 | prev = node; |
| 286 | } |
| 287 | |
| 288 | if(prev == NULL) |
| 289 | { |
| 290 | thread->next = *head; |
| 291 | thread->prev = NULL; |
| 292 | if(*head) |
| 293 | (*head)->prev = thread; |
| 294 | *head = thread; |
| 295 | } |
| 296 | else |
| 297 | { |
| 298 | if(prev->next) |
| 299 | prev->next->prev = thread; |
| 300 | thread->next = prev->next; |
| 301 | thread->prev = prev; |
| 302 | prev->next = thread; |
| 303 | } |
| 304 | assert(ThreadHead); |
| 305 | thread->state = THREAD_READY; |
| 306 | } |
| 307 | |
| 308 | |
| 309 | /******************************************/ |
| 310 | //Must be called with interrupts disabled |
| 311 | static void OS_ThreadPriorityRemove(OS_Thread_t **head, OS_Thread_t *thread) |
| 312 | { |
| 313 | assert(thread->magic[0] == THREAD_MAGIC); //check stack overflow |
| 314 | if(thread->prev == NULL) |
| 315 | *head = thread->next; |
| 316 | else |
| 317 | thread->prev->next = thread->next; |
| 318 | if(thread->next) |
| 319 | thread->next->prev = thread->prev; |
| 320 | thread->next = NULL; |
| 321 | thread->prev = NULL; |
| 322 | } |
| 323 | |
| 324 | |
| 325 | /******************************************/ |
| 326 | //Linked list of threads sorted by timeout value |
| 327 | //Must be called with interrupts disabled |
| 328 | static void OS_ThreadTimeoutInsert(OS_Thread_t *thread) |
| 329 | { |
| 330 | OS_Thread_t *node, *prev; |
| 331 | int diff; |
| 332 | |
| 333 | prev = NULL; |
| 334 | for(node = TimeoutHead; node; node = node->nextTimeout) |
| 335 | { |
| 336 | diff = thread->ticksTimeout - node->ticksTimeout; |
| 337 | if(diff <= 0) |
| 338 | break; |
| 339 | prev = node; |
| 340 | } |
| 341 | |
| 342 | if(prev == NULL) |
| 343 | { |
| 344 | thread->nextTimeout = TimeoutHead; |
| 345 | thread->prevTimeout = NULL; |
| 346 | if(TimeoutHead) |
| 347 | TimeoutHead->prevTimeout = thread; |
| 348 | TimeoutHead = thread; |
| 349 | } |
| 350 | else |
| 351 | { |
| 352 | if(prev->nextTimeout) |
| 353 | prev->nextTimeout->prevTimeout = thread; |
| 354 | thread->nextTimeout = prev->nextTimeout; |
| 355 | thread->prevTimeout = prev; |
| 356 | prev->nextTimeout = thread; |
| 357 | } |
| 358 | } |
| 359 | |
| 360 | |
| 361 | /******************************************/ |
| 362 | //Must be called with interrupts disabled |
| 363 | static void OS_ThreadTimeoutRemove(OS_Thread_t *thread) |
| 364 | { |
| 365 | if(thread->prevTimeout == NULL && TimeoutHead != thread) |
| 366 | return; //not in list |
| 367 | if(thread->prevTimeout == NULL) |
| 368 | TimeoutHead = thread->nextTimeout; |
| 369 | else |
| 370 | thread->prevTimeout->nextTimeout = thread->nextTimeout; |
| 371 | if(thread->nextTimeout) |
| 372 | thread->nextTimeout->prevTimeout = thread->prevTimeout; |
| 373 | thread->nextTimeout = NULL; |
| 374 | thread->prevTimeout = NULL; |
| 375 | } |
| 376 | |
| 377 | |
| 378 | /******************************************/ |
| 379 | //Loads highest priority thread from the ThreadHead linked list |
| 380 | //The currently running thread isn't in the ThreadHead list |
| 381 | //Must be called with interrupts disabled |
| 382 | static void OS_ThreadReschedule(int roundRobin) |
| 383 | { |
| 384 | OS_Thread_t *threadNext, *threadCurrent; |
| 385 | int rc, cpuIndex = OS_CpuIndex(); |
| 386 | |
| 387 | if(ThreadSwapEnabled == 0 || InterruptInside[cpuIndex]) |
| 388 | { |
| 389 | ThreadNeedReschedule[cpuIndex] |= 2 + roundRobin; //Reschedule later |
| 390 | return; |
| 391 | } |
| 392 | |
| 393 | //Determine which thread should run |
| 394 | threadNext = ThreadHead; |
| 395 | while(threadNext && threadNext->cpuLock != -1 && |
| 396 | threadNext->cpuLock != cpuIndex) |
| 397 | threadNext = threadNext->next; |
| 398 | if(threadNext == NULL) |
| 399 | return; |
| 400 | threadCurrent = ThreadCurrent[cpuIndex]; |
| 401 | |
| 402 | if(threadCurrent == NULL || |
| 403 | threadCurrent->state == THREAD_PEND || |
| 404 | threadCurrent->priority < threadNext->priority || |
| 405 | (roundRobin && threadCurrent->priority == threadNext->priority)) |
| 406 | { |
| 407 | //Swap threads |
| 408 | ThreadCurrent[cpuIndex] = threadNext; |
| 409 | if(threadCurrent) |
| 410 | { |
| 411 | assert(threadCurrent->magic[0] == THREAD_MAGIC); //check stack overflow |
| 412 | if(threadCurrent->state == THREAD_RUNNING) |
| 413 | OS_ThreadPriorityInsert(&ThreadHead, threadCurrent); |
| 414 | rc = setjmp(threadCurrent->env); //ANSI C call to save registers |
| 415 | if(rc) |
| 416 | return; //Returned from longjmp() |
| 417 | } |
| 418 | |
| 419 | //Remove the new running thread from the ThreadHead linked list |
| 420 | threadNext = ThreadCurrent[OS_CpuIndex()]; //removed warning |
| 421 | assert(threadNext->state == THREAD_READY); |
| 422 | OS_ThreadPriorityRemove(&ThreadHead, threadNext); |
| 423 | threadNext->state = THREAD_RUNNING; |
| 424 | threadNext->cpuIndex = OS_CpuIndex(); |
| 425 | longjmp(threadNext->env, 1); //ANSI C call to restore registers |
| 426 | } |
| 427 | } |
| 428 | |
| 429 | |
| 430 | /******************************************/ |
| 431 | void OS_ThreadCpuLock(OS_Thread_t *thread, int cpuIndex) |
| 432 | { |
| 433 | thread->cpuLock = cpuIndex; |
| 434 | if(thread == OS_ThreadSelf() && cpuIndex != (int)OS_CpuIndex()) |
| 435 | OS_ThreadSleep(1); |
| 436 | } |
| 437 | |
| 438 | |
| 439 | /******************************************/ |
| 440 | static void OS_ThreadInit(void *arg) |
| 441 | { |
| 442 | uint32 cpuIndex = OS_CpuIndex(); |
| 443 | (void)arg; |
| 444 | |
| 445 | OS_CriticalEnd(1); |
| 446 | ThreadCurrent[cpuIndex]->funcPtr(ThreadCurrent[cpuIndex]->arg); |
| 447 | OS_ThreadExit(); |
| 448 | } |
| 449 | |
| 450 | |
| 451 | /******************************************/ |
| 452 | //Stops warning "argument X might be clobbered by `longjmp'" |
| 453 | static void OS_ThreadRegsInit(jmp_buf env) |
| 454 | { |
| 455 | setjmp(env); //ANSI C call to save registers |
| 456 | } |
| 457 | |
| 458 | |
| 459 | /******************************************/ |
| 460 | OS_Thread_t *OS_ThreadCreate(const char *name, |
| 461 | OS_FuncPtr_t funcPtr, |
| 462 | void *arg, |
| 463 | uint32 priority, |
| 464 | uint32 stackSize) |
| 465 | { |
| 466 | OS_Thread_t *thread; |
| 467 | uint8 *stack; |
| 468 | jmp_buf2 *env; |
| 469 | uint32 state; |
| 470 | |
| 471 | OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER); |
| 472 | if(NeedToFree) |
| 473 | OS_HeapFree(NeedToFree); |
| 474 | NeedToFree = NULL; |
| 475 | OS_SemaphorePost(SemaphoreRelease); |
| 476 | |
| 477 | if(stackSize == 0) |
| 478 | stackSize = STACK_SIZE_DEFAULT; |
| 479 | if(stackSize < STACK_SIZE_MINIMUM) |
| 480 | stackSize = STACK_SIZE_MINIMUM; |
| 481 | thread = (OS_Thread_t*)OS_HeapMalloc(NULL, sizeof(OS_Thread_t) + stackSize); |
| 482 | assert(thread); |
| 483 | if(thread == NULL) |
| 484 | return NULL; |
| 485 | memset(thread, 0, sizeof(OS_Thread_t)); |
| 486 | stack = (uint8*)(thread + 1); |
| 487 | memset(stack, 0xcd, stackSize); |
| 488 | |
| 489 | thread->name = name; |
| 490 | thread->state = THREAD_READY; |
| 491 | thread->cpuLock = -1; |
| 492 | thread->funcPtr = funcPtr; |
| 493 | thread->arg = arg; |
| 494 | thread->priority = priority; |
| 495 | thread->semaphorePending = NULL; |
| 496 | thread->returnCode = 0; |
| 497 | if(OS_ThreadSelf()) |
| 498 | { |
| 499 | thread->processId = OS_ThreadSelf()->processId; |
| 500 | thread->heap = OS_ThreadSelf()->heap; |
| 501 | } |
| 502 | else |
| 503 | { |
| 504 | thread->processId = 0; |
| 505 | thread->heap = NULL; |
| 506 | } |
| 507 | thread->next = NULL; |
| 508 | thread->prev = NULL; |
| 509 | thread->nextTimeout = NULL; |
| 510 | thread->prevTimeout = NULL; |
| 511 | thread->magic[0] = THREAD_MAGIC; |
| 512 | |
| 513 | OS_ThreadRegsInit(thread->env); |
| 514 | env = (jmp_buf2*)thread->env; |
| 515 | env->sp = (uint32)stack + stackSize - 24; //minimum stack frame size |
| 516 | env->pc = (uint32)OS_ThreadInit; |
| 517 | |
| 518 | state = OS_CriticalBegin(); |
| 519 | OS_ThreadPriorityInsert(&ThreadHead, thread); |
| 520 | OS_ThreadReschedule(0); |
| 521 | OS_CriticalEnd(state); |
| 522 | return thread; |
| 523 | } |
| 524 | |
| 525 | |
| 526 | /******************************************/ |
| 527 | void OS_ThreadExit(void) |
| 528 | { |
| 529 | uint32 state, cpuIndex = OS_CpuIndex(); |
| 530 | |
| 531 | for(;;) |
| 532 | { |
| 533 | OS_SemaphorePend(SemaphoreRelease, OS_WAIT_FOREVER); |
| 534 | if(NeedToFree) |
| 535 | OS_HeapFree(NeedToFree); |
| 536 | NeedToFree = NULL; |
| 537 | OS_SemaphorePost(SemaphoreRelease); |
| 538 | |
| 539 | state = OS_CriticalBegin(); |
| 540 | if(NeedToFree) |
| 541 | { |
| 542 | OS_CriticalEnd(state); |
| 543 | continue; |
| 544 | } |
| 545 | ThreadCurrent[cpuIndex]->state = THREAD_PEND; |
| 546 | NeedToFree = ThreadCurrent[cpuIndex]; |
| 547 | OS_ThreadReschedule(0); |
| 548 | OS_CriticalEnd(state); |
| 549 | } |
| 550 | } |
| 551 | |
| 552 | |
| 553 | /******************************************/ |
| 554 | OS_Thread_t *OS_ThreadSelf(void) |
| 555 | { |
| 556 | return ThreadCurrent[OS_CpuIndex()]; |
| 557 | } |
| 558 | |
| 559 | |
| 560 | /******************************************/ |
| 561 | void OS_ThreadSleep(int ticks) |
| 562 | { |
| 563 | OS_SemaphorePend(SemaphoreSleep, ticks); |
| 564 | } |
| 565 | |
| 566 | |
| 567 | /******************************************/ |
| 568 | uint32 OS_ThreadTime(void) |
| 569 | { |
| 570 | return ThreadTime; |
| 571 | } |
| 572 | |
| 573 | |
| 574 | /******************************************/ |
| 575 | void OS_ThreadInfoSet(OS_Thread_t *thread, uint32 index, void *Info) |
| 576 | { |
| 577 | if(index < INFO_COUNT) |
| 578 | thread->info[index] = Info; |
| 579 | } |
| 580 | |
| 581 | |
| 582 | /******************************************/ |
| 583 | void *OS_ThreadInfoGet(OS_Thread_t *thread, uint32 index) |
| 584 | { |
| 585 | if(index < INFO_COUNT) |
| 586 | return thread->info[index]; |
| 587 | return NULL; |
| 588 | } |
| 589 | |
| 590 | |
| 591 | /******************************************/ |
| 592 | uint32 OS_ThreadPriorityGet(OS_Thread_t *thread) |
| 593 | { |
| 594 | return thread->priority; |
| 595 | } |
| 596 | |
| 597 | |
| 598 | /******************************************/ |
| 599 | void OS_ThreadPrioritySet(OS_Thread_t *thread, uint32 priority) |
| 600 | { |
| 601 | uint32 state; |
| 602 | state = OS_CriticalBegin(); |
| 603 | thread->priority = priority; |
| 604 | if(thread->state == THREAD_READY) |
| 605 | { |
| 606 | OS_ThreadPriorityRemove(&ThreadHead, thread); |
| 607 | OS_ThreadPriorityInsert(&ThreadHead, thread); |
| 608 | OS_ThreadReschedule(0); |
| 609 | } |
| 610 | OS_CriticalEnd(state); |
| 611 | } |
| 612 | |
| 613 | |
| 614 | /******************************************/ |
| 615 | void OS_ThreadProcessId(OS_Thread_t *thread, uint32 processId, OS_Heap_t *heap) |
| 616 | { |
| 617 | thread->processId = processId; |
| 618 | thread->heap = heap; |
| 619 | } |
| 620 | |
| 621 | |
| 622 | /******************************************/ |
| 623 | //Must be called with interrupts disabled |
| 624 | void OS_ThreadTick(void *Arg) |
| 625 | { |
| 626 | OS_Thread_t *thread; |
| 627 | OS_Semaphore_t *semaphore; |
| 628 | int diff; |
| 629 | (void)Arg; |
| 630 | |
| 631 | ++ThreadTime; |
| 632 | while(TimeoutHead) |
| 633 | { |
| 634 | thread = TimeoutHead; |
| 635 | diff = ThreadTime - thread->ticksTimeout; |
| 636 | if(diff < 0) |
| 637 | break; |
| 638 | OS_ThreadTimeoutRemove(thread); |
| 639 | semaphore = thread->semaphorePending; |
| 640 | ++semaphore->count; |
| 641 | thread->semaphorePending = NULL; |
| 642 | thread->returnCode = -1; |
| 643 | OS_ThreadPriorityRemove(&semaphore->threadHead, thread); |
| 644 | OS_ThreadPriorityInsert(&ThreadHead, thread); |
| 645 | } |
| 646 | OS_ThreadReschedule(1); |
| 647 | } |
| 648 | |
| 649 | |
| 650 | |
| 651 | /***************** Semaphore **************/ |
| 652 | /******************************************/ |
| 653 | OS_Semaphore_t *OS_SemaphoreCreate(const char *name, uint32 count) |
| 654 | { |
| 655 | OS_Semaphore_t *semaphore; |
| 656 | static int semCount = 0; |
| 657 | |
| 658 | if(semCount < SEM_RESERVED_COUNT) |
| 659 | semaphore = &SemaphoreReserved[semCount++]; //Heap not ready yet |
| 660 | else |
| 661 | semaphore = (OS_Semaphore_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Semaphore_t)); |
| 662 | assert(semaphore); |
| 663 | if(semaphore == NULL) |
| 664 | return NULL; |
| 665 | |
| 666 | semaphore->name = name; |
| 667 | semaphore->threadHead = NULL; |
| 668 | semaphore->count = count; |
| 669 | return semaphore; |
| 670 | } |
| 671 | |
| 672 | |
| 673 | /******************************************/ |
| 674 | void OS_SemaphoreDelete(OS_Semaphore_t *semaphore) |
| 675 | { |
| 676 | while(semaphore->threadHead) |
| 677 | OS_SemaphorePost(semaphore); |
| 678 | OS_HeapFree(semaphore); |
| 679 | } |
| 680 | |
| 681 | |
| 682 | /******************************************/ |
| 683 | int OS_SemaphorePend(OS_Semaphore_t *semaphore, int ticks) |
| 684 | { |
| 685 | uint32 state, cpuIndex; |
| 686 | OS_Thread_t *thread; |
| 687 | int returnCode=0; |
| 688 | |
| 689 | assert(semaphore); |
| 690 | assert(InterruptInside[OS_CpuIndex()] == 0); |
| 691 | state = OS_CriticalBegin(); |
| 692 | if(--semaphore->count < 0) |
| 693 | { |
| 694 | if(ticks == 0) |
| 695 | { |
| 696 | ++semaphore->count; |
| 697 | OS_CriticalEnd(state); |
| 698 | return -1; |
| 699 | } |
| 700 | cpuIndex = OS_CpuIndex(); |
| 701 | thread = ThreadCurrent[cpuIndex]; |
| 702 | assert(thread); |
| 703 | thread->semaphorePending = semaphore; |
| 704 | thread->ticksTimeout = ticks + OS_ThreadTime(); |
| 705 | //FYI: The current thread isn't in the ThreadHead linked list |
| 706 | OS_ThreadPriorityInsert(&semaphore->threadHead, thread); |
| 707 | thread->state = THREAD_PEND; |
| 708 | if(ticks != OS_WAIT_FOREVER) |
| 709 | OS_ThreadTimeoutInsert(thread); |
| 710 | assert(ThreadHead); |
| 711 | OS_ThreadReschedule(0); |
| 712 | returnCode = thread->returnCode; |
| 713 | } |
| 714 | OS_CriticalEnd(state); |
| 715 | return returnCode; |
| 716 | } |
| 717 | |
| 718 | |
| 719 | /******************************************/ |
| 720 | void OS_SemaphorePost(OS_Semaphore_t *semaphore) |
| 721 | { |
| 722 | uint32 state; |
| 723 | OS_Thread_t *thread; |
| 724 | |
| 725 | assert(semaphore); |
| 726 | state = OS_CriticalBegin(); |
| 727 | if(++semaphore->count <= 0) |
| 728 | { |
| 729 | thread = semaphore->threadHead; |
| 730 | OS_ThreadTimeoutRemove(thread); |
| 731 | OS_ThreadPriorityRemove(&semaphore->threadHead, thread); |
| 732 | OS_ThreadPriorityInsert(&ThreadHead, thread); |
| 733 | thread->semaphorePending = NULL; |
| 734 | thread->returnCode = 0; |
| 735 | OS_ThreadReschedule(0); |
| 736 | } |
| 737 | OS_CriticalEnd(state); |
| 738 | } |
| 739 | |
| 740 | |
| 741 | |
| 742 | /***************** Mutex ******************/ |
| 743 | /******************************************/ |
| 744 | OS_Mutex_t *OS_MutexCreate(const char *name) |
| 745 | { |
| 746 | OS_Mutex_t *mutex; |
| 747 | |
| 748 | mutex = (OS_Mutex_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Mutex_t)); |
| 749 | if(mutex == NULL) |
| 750 | return NULL; |
| 751 | mutex->semaphore = OS_SemaphoreCreate(name, 1); |
| 752 | if(mutex->semaphore == NULL) |
| 753 | return NULL; |
| 754 | mutex->thread = NULL; |
| 755 | mutex->count = 0; |
| 756 | return mutex; |
| 757 | } |
| 758 | |
| 759 | |
| 760 | /******************************************/ |
| 761 | void OS_MutexDelete(OS_Mutex_t *mutex) |
| 762 | { |
| 763 | OS_SemaphoreDelete(mutex->semaphore); |
| 764 | OS_HeapFree(mutex); |
| 765 | } |
| 766 | |
| 767 | |
| 768 | /******************************************/ |
| 769 | void OS_MutexPend(OS_Mutex_t *mutex) |
| 770 | { |
| 771 | OS_Thread_t *thread; |
| 772 | |
| 773 | assert(mutex); |
| 774 | thread = OS_ThreadSelf(); |
| 775 | if(thread == mutex->thread) |
| 776 | { |
| 777 | ++mutex->count; |
| 778 | return; |
| 779 | } |
| 780 | OS_SemaphorePend(mutex->semaphore, OS_WAIT_FOREVER); |
| 781 | mutex->thread = thread; |
| 782 | mutex->count = 1; |
| 783 | } |
| 784 | |
| 785 | |
| 786 | /******************************************/ |
| 787 | void OS_MutexPost(OS_Mutex_t *mutex) |
| 788 | { |
| 789 | assert(mutex); |
| 790 | assert(mutex->thread == OS_ThreadSelf()); |
| 791 | assert(mutex->count > 0); |
| 792 | if(--mutex->count <= 0) |
| 793 | { |
| 794 | mutex->thread = NULL; |
| 795 | OS_SemaphorePost(mutex->semaphore); |
| 796 | } |
| 797 | } |
| 798 | |
| 799 | |
| 800 | |
| 801 | /***************** MQueue *****************/ |
| 802 | /******************************************/ |
| 803 | OS_MQueue_t *OS_MQueueCreate(const char *name, |
| 804 | int messageCount, |
| 805 | int messageBytes) |
| 806 | { |
| 807 | OS_MQueue_t *queue; |
| 808 | int size; |
| 809 | |
| 810 | size = messageBytes / sizeof(uint32); |
| 811 | queue = (OS_MQueue_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_MQueue_t) + |
| 812 | messageCount * size * 4); |
| 813 | if(queue == NULL) |
| 814 | return queue; |
| 815 | queue->name = name; |
| 816 | queue->semaphore = OS_SemaphoreCreate(name, 0); |
| 817 | if(queue->semaphore == NULL) |
| 818 | return NULL; |
| 819 | queue->count = messageCount; |
| 820 | queue->size = size; |
| 821 | queue->used = 0; |
| 822 | queue->read = 0; |
| 823 | queue->write = 0; |
| 824 | return queue; |
| 825 | } |
| 826 | |
| 827 | |
| 828 | /******************************************/ |
| 829 | void OS_MQueueDelete(OS_MQueue_t *mQueue) |
| 830 | { |
| 831 | OS_SemaphoreDelete(mQueue->semaphore); |
| 832 | OS_HeapFree(mQueue); |
| 833 | } |
| 834 | |
| 835 | |
| 836 | /******************************************/ |
| 837 | int OS_MQueueSend(OS_MQueue_t *mQueue, void *message) |
| 838 | { |
| 839 | uint32 state, *dst, *src; |
| 840 | int i; |
| 841 | |
| 842 | assert(mQueue); |
| 843 | src = (uint32*)message; |
| 844 | state = OS_CriticalBegin(); |
| 845 | if(++mQueue->used > mQueue->count) |
| 846 | { |
| 847 | --mQueue->used; |
| 848 | OS_CriticalEnd(state); |
| 849 | return -1; |
| 850 | } |
| 851 | dst = (uint32*)(mQueue + 1) + mQueue->write * mQueue->size; |
| 852 | for(i = 0; i < mQueue->size; ++i) |
| 853 | dst[i] = src[i]; |
| 854 | if(++mQueue->write >= mQueue->count) |
| 855 | mQueue->write = 0; |
| 856 | OS_CriticalEnd(state); |
| 857 | OS_SemaphorePost(mQueue->semaphore); |
| 858 | return 0; |
| 859 | } |
| 860 | |
| 861 | |
| 862 | /******************************************/ |
| 863 | int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks) |
| 864 | { |
| 865 | uint32 state, *dst, *src; |
| 866 | int i, rc; |
| 867 | |
| 868 | assert(mQueue); |
| 869 | dst = (uint32*)message; |
| 870 | rc = OS_SemaphorePend(mQueue->semaphore, ticks); |
| 871 | if(rc) |
| 872 | return rc; |
| 873 | state = OS_CriticalBegin(); |
| 874 | --mQueue->used; |
| 875 | src = (uint32*)(mQueue + 1) + mQueue->read * mQueue->size; |
| 876 | for(i = 0; i < mQueue->size; ++i) |
| 877 | dst[i] = src[i]; |
| 878 | if(++mQueue->read >= mQueue->count) |
| 879 | mQueue->read = 0; |
| 880 | OS_CriticalEnd(state); |
| 881 | return 0; |
| 882 | } |
| 883 | |
| 884 | |
| 885 | |
| 886 | /***************** Jobs *******************/ |
| 887 | /******************************************/ |
| 888 | typedef void (*JobFunc_t)(); |
| 889 | static OS_MQueue_t *jobQueue; |
| 890 | static OS_Thread_t *jobThread; |
| 891 | |
| 892 | static void JobThread(void *arg) |
| 893 | { |
| 894 | uint32 message[4]; |
| 895 | JobFunc_t funcPtr; |
| 896 | (void)arg; |
| 897 | for(;;) |
| 898 | { |
| 899 | OS_MQueueGet(jobQueue, message, OS_WAIT_FOREVER); |
| 900 | funcPtr = (JobFunc_t)message[0]; |
| 901 | funcPtr(message[1], message[2], message[3]); |
| 902 | } |
| 903 | } |
| 904 | |
| 905 | |
| 906 | /******************************************/ |
| 907 | void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2) |
| 908 | { |
| 909 | uint32 message[4]; |
| 910 | int rc; |
| 911 | |
| 912 | OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
| 913 | if(jobThread == NULL) |
| 914 | { |
| 915 | jobQueue = OS_MQueueCreate("job", 100, 16); |
| 916 | jobThread = OS_ThreadCreate("job", JobThread, NULL, 150, 4000); |
| 917 | } |
| 918 | OS_SemaphorePost(SemaphoreLock); |
| 919 | |
| 920 | message[0] = (uint32)funcPtr; |
| 921 | message[1] = (uint32)arg0; |
| 922 | message[2] = (uint32)arg1; |
| 923 | message[3] = (uint32)arg2; |
| 924 | rc = OS_MQueueSend(jobQueue, message); |
| 925 | } |
| 926 | |
| 927 | |
| 928 | /***************** Timer ******************/ |
| 929 | /******************************************/ |
| 930 | static void OS_TimerThread(void *arg) |
| 931 | { |
| 932 | uint32 timeNow; |
| 933 | int diff, ticks; |
| 934 | uint32 message[8]; |
| 935 | OS_Timer_t *timer; |
| 936 | (void)arg; |
| 937 | |
| 938 | timeNow = OS_ThreadTime(); |
| 939 | for(;;) |
| 940 | { |
| 941 | //Determine how long to sleep |
| 942 | OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
| 943 | if(TimerHead) |
| 944 | ticks = TimerHead->ticksTimeout - timeNow; |
| 945 | else |
| 946 | ticks = OS_WAIT_FOREVER; |
| 947 | OS_SemaphorePost(SemaphoreLock); |
| 948 | OS_SemaphorePend(SemaphoreTimer, ticks); |
| 949 | |
| 950 | //Send messages for all timed out timers |
| 951 | timeNow = OS_ThreadTime(); |
| 952 | for(;;) |
| 953 | { |
| 954 | timer = NULL; |
| 955 | OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
| 956 | if(TimerHead) |
| 957 | { |
| 958 | diff = timeNow - TimerHead->ticksTimeout; |
| 959 | if(diff >= 0) |
| 960 | timer = TimerHead; |
| 961 | } |
| 962 | OS_SemaphorePost(SemaphoreLock); |
| 963 | if(timer == NULL) |
| 964 | break; |
| 965 | if(timer->ticksRestart) |
| 966 | OS_TimerStart(timer, timer->ticksRestart, timer->ticksRestart); |
| 967 | else |
| 968 | OS_TimerStop(timer); |
| 969 | |
| 970 | if(timer->callback) |
| 971 | timer->callback(timer, timer->info); |
| 972 | else |
| 973 | { |
| 974 | //Send message |
| 975 | message[0] = MESSAGE_TYPE_TIMER; |
| 976 | message[1] = (uint32)timer; |
| 977 | message[2] = timer->info; |
| 978 | OS_MQueueSend(timer->mqueue, message); |
| 979 | } |
| 980 | } |
| 981 | } |
| 982 | } |
| 983 | |
| 984 | |
| 985 | /******************************************/ |
| 986 | OS_Timer_t *OS_TimerCreate(const char *name, OS_MQueue_t *mQueue, uint32 info) |
| 987 | { |
| 988 | OS_Timer_t *timer; |
| 989 | |
| 990 | OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
| 991 | if(SemaphoreTimer == NULL) |
| 992 | { |
| 993 | SemaphoreTimer = OS_SemaphoreCreate("Timer", 0); |
| 994 | OS_ThreadCreate("Timer", OS_TimerThread, NULL, 250, 2000); |
| 995 | } |
| 996 | OS_SemaphorePost(SemaphoreLock); |
| 997 | |
| 998 | timer = (OS_Timer_t*)OS_HeapMalloc(HEAP_SYSTEM, sizeof(OS_Timer_t)); |
| 999 | if(timer == NULL) |
| 1000 | return NULL; |
| 1001 | timer->name = name; |
| 1002 | timer->callback = NULL; |
| 1003 | timer->mqueue = mQueue; |
| 1004 | timer->next = NULL; |
| 1005 | timer->prev = NULL; |
| 1006 | timer->info = info; |
| 1007 | timer->active = 0; |
| 1008 | return timer; |
| 1009 | } |
| 1010 | |
| 1011 | |
| 1012 | /******************************************/ |
| 1013 | void OS_TimerDelete(OS_Timer_t *timer) |
| 1014 | { |
| 1015 | OS_TimerStop(timer); |
| 1016 | OS_HeapFree(timer); |
| 1017 | } |
| 1018 | |
| 1019 | |
| 1020 | /******************************************/ |
| 1021 | void OS_TimerCallback(OS_Timer_t *timer, OS_TimerFuncPtr_t callback) |
| 1022 | { |
| 1023 | timer->callback = callback; |
| 1024 | } |
| 1025 | |
| 1026 | |
| 1027 | /******************************************/ |
| 1028 | //Must not be called from an ISR |
| 1029 | void OS_TimerStart(OS_Timer_t *timer, uint32 ticks, uint32 ticksRestart) |
| 1030 | { |
| 1031 | OS_Timer_t *node, *prev; |
| 1032 | int diff, check=0; |
| 1033 | |
| 1034 | assert(timer); |
| 1035 | assert(InterruptInside[OS_CpuIndex()] == 0); |
| 1036 | ticks += OS_ThreadTime(); |
| 1037 | if(timer->active) |
| 1038 | OS_TimerStop(timer); |
| 1039 | OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
| 1040 | if(timer->active) |
| 1041 | { |
| 1042 | //Prevent race condition |
| 1043 | OS_SemaphorePost(SemaphoreLock); |
| 1044 | return; |
| 1045 | } |
| 1046 | timer->ticksTimeout = ticks; |
| 1047 | timer->ticksRestart = ticksRestart; |
| 1048 | timer->active = 1; |
| 1049 | prev = NULL; |
| 1050 | for(node = TimerHead; node; node = node->next) |
| 1051 | { |
| 1052 | diff = ticks - node->ticksTimeout; |
| 1053 | if(diff <= 0) |
| 1054 | break; |
| 1055 | prev = node; |
| 1056 | } |
| 1057 | timer->next = node; |
| 1058 | timer->prev = prev; |
| 1059 | if(node) |
| 1060 | node->prev = timer; |
| 1061 | if(prev == NULL) |
| 1062 | { |
| 1063 | TimerHead = timer; |
| 1064 | check = 1; |
| 1065 | } |
| 1066 | else |
| 1067 | prev->next = timer; |
| 1068 | OS_SemaphorePost(SemaphoreLock); |
| 1069 | if(check) |
| 1070 | OS_SemaphorePost(SemaphoreTimer); |
| 1071 | } |
| 1072 | |
| 1073 | |
| 1074 | /******************************************/ |
| 1075 | //Must not be called from an ISR |
| 1076 | void OS_TimerStop(OS_Timer_t *timer) |
| 1077 | { |
| 1078 | assert(timer); |
| 1079 | assert(InterruptInside[OS_CpuIndex()] == 0); |
| 1080 | OS_SemaphorePend(SemaphoreLock, OS_WAIT_FOREVER); |
| 1081 | if(timer->active) |
| 1082 | { |
| 1083 | timer->active = 0; |
| 1084 | if(timer->prev == NULL) |
| 1085 | TimerHead = timer->next; |
| 1086 | else |
| 1087 | timer->prev->next = timer->next; |
| 1088 | if(timer->next) |
| 1089 | timer->next->prev = timer->prev; |
| 1090 | } |
| 1091 | OS_SemaphorePost(SemaphoreLock); |
| 1092 | } |
| 1093 | |
| 1094 | |
| 1095 | /***************** ISR ********************/ |
| 1096 | /******************************************/ |
| 1097 | void OS_InterruptServiceRoutine(uint32 status, uint32 *stack) |
| 1098 | { |
| 1099 | int i; |
| 1100 | uint32 state, cpuIndex = OS_CpuIndex(); |
| 1101 | |
| 1102 | if(status == 0 && Isr[31]) |
| 1103 | Isr[31](stack); //SYSCALL or BREAK |
| 1104 | |
| 1105 | InterruptInside[cpuIndex] = 1; |
| 1106 | i = 0; |
| 1107 | do |
| 1108 | { |
| 1109 | if(status & 1) |
| 1110 | { |
| 1111 | if(Isr[i]) |
| 1112 | Isr[i](stack); |
| 1113 | else |
| 1114 | OS_InterruptMaskClear(1 << i); |
| 1115 | } |
| 1116 | status >>= 1; |
| 1117 | ++i; |
| 1118 | } while(status); |
| 1119 | InterruptInside[cpuIndex] = 0; |
| 1120 | |
| 1121 | state = OS_SpinLock(); |
| 1122 | if(ThreadNeedReschedule[cpuIndex]) |
| 1123 | OS_ThreadReschedule(ThreadNeedReschedule[cpuIndex] & 1); |
| 1124 | OS_SpinUnlock(state); |
| 1125 | } |
| 1126 | |
| 1127 | |
| 1128 | /******************************************/ |
| 1129 | void OS_InterruptRegister(uint32 mask, OS_FuncPtr_t funcPtr) |
| 1130 | { |
| 1131 | int i; |
| 1132 | |
| 1133 | for(i = 0; i < 32; ++i) |
| 1134 | { |
| 1135 | if(mask & (1 << i)) |
| 1136 | Isr[i] = funcPtr; |
| 1137 | } |
| 1138 | } |
| 1139 | |
| 1140 | |
| 1141 | /******************************************/ |
| 1142 | //Plasma hardware dependent |
| 1143 | uint32 OS_InterruptStatus(void) |
| 1144 | { |
| 1145 | return MemoryRead(IRQ_STATUS); |
| 1146 | } |
| 1147 | |
| 1148 | |
| 1149 | /******************************************/ |
| 1150 | //Plasma hardware dependent |
| 1151 | uint32 OS_InterruptMaskSet(uint32 mask) |
| 1152 | { |
| 1153 | uint32 state; |
| 1154 | state = OS_CriticalBegin(); |
| 1155 | mask |= MemoryRead(IRQ_MASK); |
| 1156 | MemoryWrite(IRQ_MASK, mask); |
| 1157 | OS_CriticalEnd(state); |
| 1158 | return mask; |
| 1159 | } |
| 1160 | |
| 1161 | |
| 1162 | /******************************************/ |
| 1163 | //Plasma hardware dependent |
| 1164 | uint32 OS_InterruptMaskClear(uint32 mask) |
| 1165 | { |
| 1166 | uint32 state; |
| 1167 | state = OS_CriticalBegin(); |
| 1168 | mask = MemoryRead(IRQ_MASK) & ~mask; |
| 1169 | MemoryWrite(IRQ_MASK, mask); |
| 1170 | OS_CriticalEnd(state); |
| 1171 | return mask; |
| 1172 | } |
| 1173 | |
| 1174 | |
| 1175 | /**************** Init ********************/ |
| 1176 | /******************************************/ |
| 1177 | static volatile uint32 IdleCount; |
| 1178 | static void OS_IdleThread(void *arg) |
| 1179 | { |
| 1180 | (void)arg; |
| 1181 | |
| 1182 | //Don't block in the idle thread! |
| 1183 | for(;;) |
| 1184 | { |
| 1185 | ++IdleCount; |
| 1186 | } |
| 1187 | } |
| 1188 | |
| 1189 | |
| 1190 | /******************************************/ |
| 1191 | #ifndef DISABLE_IRQ_SIM |
| 1192 | static void OS_IdleSimulateIsr(void *arg) |
| 1193 | { |
| 1194 | uint32 count=0, value; |
| 1195 | (void)arg; |
| 1196 | |
| 1197 | for(;;) |
| 1198 | { |
| 1199 | MemoryRead(IRQ_MASK + 4); //calls Sleep(10) |
| 1200 | #if WIN32 |
| 1201 | while(OS_InterruptMaskSet(0) & IRQ_UART_WRITE_AVAILABLE) |
| 1202 | OS_InterruptServiceRoutine(IRQ_UART_WRITE_AVAILABLE, 0); |
| 1203 | #endif |
| 1204 | value = OS_InterruptMaskSet(0) & 0xf; |
| 1205 | if(value) |
| 1206 | OS_InterruptServiceRoutine(value, 0); |
| 1207 | ++count; |
| 1208 | } |
| 1209 | } |
| 1210 | #endif //DISABLE_IRQ_SIM |
| 1211 | |
| 1212 | |
| 1213 | /******************************************/ |
| 1214 | //Plasma hardware dependent |
| 1215 | static void OS_ThreadTickToggle(void *arg) |
| 1216 | { |
| 1217 | uint32 status, mask, state; |
| 1218 | |
| 1219 | //Toggle looking for IRQ_COUNTER18 or IRQ_COUNTER18_NOT |
| 1220 | state = OS_SpinLock(); |
| 1221 | status = MemoryRead(IRQ_STATUS) & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT); |
| 1222 | mask = MemoryRead(IRQ_MASK) | IRQ_COUNTER18 | IRQ_COUNTER18_NOT; |
| 1223 | mask &= ~status; |
| 1224 | MemoryWrite(IRQ_MASK, mask); |
| 1225 | OS_ThreadTick(arg); |
| 1226 | OS_SpinUnlock(state); |
| 1227 | } |
| 1228 | |
| 1229 | |
| 1230 | /******************************************/ |
| 1231 | void OS_Init(uint32 *heapStorage, uint32 bytes) |
| 1232 | { |
| 1233 | int i; |
| 1234 | OS_AsmInterruptInit(); //Patch interrupt vector |
| 1235 | OS_InterruptMaskClear(0xffffffff); //Disable interrupts |
| 1236 | HeapArray[0] = OS_HeapCreate("Default", heapStorage, bytes); |
| 1237 | HeapArray[1] = HeapArray[0]; |
| 1238 | SemaphoreSleep = OS_SemaphoreCreate("Sleep", 0); |
| 1239 | SemaphoreRelease = OS_SemaphoreCreate("Release", 1); |
| 1240 | SemaphoreLock = OS_SemaphoreCreate("Lock", 1); |
| 1241 | for(i = 0; i < OS_CPU_COUNT; ++i) |
| 1242 | OS_ThreadCreate("Idle", OS_IdleThread, NULL, 0, 256); |
| 1243 | #ifndef DISABLE_IRQ_SIM |
| 1244 | if((OS_InterruptStatus() & (IRQ_COUNTER18 | IRQ_COUNTER18_NOT)) == 0) |
| 1245 | { |
| 1246 | //Detected that running in simulator so create SimIsr thread |
| 1247 | UartPrintfCritical("SimIsr\n"); |
| 1248 | OS_ThreadCreate("SimIsr", OS_IdleSimulateIsr, NULL, 1, 0); |
| 1249 | } |
| 1250 | #endif //DISABLE_IRQ_SIM |
| 1251 | //Plasma hardware dependent |
| 1252 | OS_InterruptRegister(IRQ_COUNTER18 | IRQ_COUNTER18_NOT, OS_ThreadTickToggle); |
| 1253 | OS_InterruptMaskSet(IRQ_COUNTER18 | IRQ_COUNTER18_NOT); |
| 1254 | } |
| 1255 | |
| 1256 | |
| 1257 | /******************************************/ |
| 1258 | void OS_Start(void) |
| 1259 | { |
| 1260 | ThreadSwapEnabled = 1; |
| 1261 | (void)OS_SpinLock(); |
| 1262 | OS_ThreadReschedule(1); |
| 1263 | } |
| 1264 | |
| 1265 | |
| 1266 | /******************************************/ |
| 1267 | //Place breakpoint here |
| 1268 | void OS_Assert(void) |
| 1269 | { |
| 1270 | } |
| 1271 | |
| 1272 | |
| 1273 | #if OS_CPU_COUNT > 1 |
| 1274 | static uint8 SpinLockArray[OS_CPU_COUNT]; |
| 1275 | /******************************************/ |
| 1276 | uint32 OS_CpuIndex(void) |
| 1277 | { |
| 1278 | return 0; //0 to OS_CPU_COUNT-1 |
| 1279 | } |
| 1280 | |
| 1281 | |
| 1282 | /******************************************/ |
| 1283 | //Symmetric Multiprocessing Spin Lock Mutex |
| 1284 | uint32 OS_SpinLock(void) |
| 1285 | { |
| 1286 | uint32 state, cpuIndex, i, j, ok, delay; |
| 1287 | |
| 1288 | cpuIndex = OS_CpuIndex(); |
| 1289 | delay = cpuIndex + 8; |
| 1290 | state = OS_AsmInterruptEnable(0); |
| 1291 | do |
| 1292 | { |
| 1293 | ok = 1; |
| 1294 | if(++SpinLockArray[cpuIndex] == 1) |
| 1295 | { |
| 1296 | for(i = 0; i < OS_CPU_COUNT; ++i) |
| 1297 | { |
| 1298 | if(i != cpuIndex && SpinLockArray[i]) |
| 1299 | ok = 0; |
| 1300 | } |
| 1301 | if(ok == 0) |
| 1302 | { |
| 1303 | SpinLockArray[cpuIndex] = 0; |
| 1304 | for(j = 0; j < delay; ++j) //wait a bit |
| 1305 | ++i; |
| 1306 | if(delay < 128) |
| 1307 | delay <<= 1; |
| 1308 | } |
| 1309 | } |
| 1310 | } while(ok == 0); |
| 1311 | return state; |
| 1312 | } |
| 1313 | |
| 1314 | |
| 1315 | /******************************************/ |
| 1316 | void OS_SpinUnlock(uint32 state) |
| 1317 | { |
| 1318 | uint32 cpuIndex; |
| 1319 | cpuIndex = OS_CpuIndex(); |
| 1320 | if(--SpinLockArray[cpuIndex] == 0) |
| 1321 | OS_AsmInterruptEnable(state); |
| 1322 | |
| 1323 | assert(SpinLockArray[cpuIndex] < 10); |
| 1324 | } |
| 1325 | #endif //OS_CPU_COUNT > 1 |
| 1326 | |
| 1327 | |
| 1328 | /************** WIN32/Linux Support *************/ |
| 1329 | #ifdef WIN32 |
| 1330 | #ifdef LINUX |
| 1331 | #define putch putchar |
| 1332 | #undef _LIBC |
| 1333 | #undef kbhit |
| 1334 | #undef getch |
| 1335 | #define UartPrintf UartPrintf2 |
| 1336 | #define UartScanf UartScanf2 |
| 1337 | #include <stdio.h> |
| 1338 | #include <stdlib.h> |
| 1339 | #include <termios.h> |
| 1340 | #include <unistd.h> |
| 1341 | void Sleep(unsigned int value) |
| 1342 | { |
| 1343 | usleep(value * 1000); |
| 1344 | } |
| 1345 | |
| 1346 | int kbhit(void) |
| 1347 | { |
| 1348 | struct termios oldt, newt; |
| 1349 | struct timeval tv; |
| 1350 | fd_set read_fd; |
| 1351 | |
| 1352 | tcgetattr(STDIN_FILENO, &oldt); |
| 1353 | newt = oldt; |
| 1354 | newt.c_lflag &= ~(ICANON | ECHO); |
| 1355 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); |
| 1356 | tv.tv_sec=0; |
| 1357 | tv.tv_usec=0; |
| 1358 | FD_ZERO(&read_fd); |
| 1359 | FD_SET(0,&read_fd); |
| 1360 | if(select(1, &read_fd, NULL, NULL, &tv) == -1) |
| 1361 | return 0; |
| 1362 | if(FD_ISSET(0,&read_fd)) |
| 1363 | return 1; |
| 1364 | return 0; |
| 1365 | } |
| 1366 | |
| 1367 | int getch(void) |
| 1368 | { |
| 1369 | struct termios oldt, newt; |
| 1370 | int ch; |
| 1371 | |
| 1372 | tcgetattr(STDIN_FILENO, &oldt); |
| 1373 | newt = oldt; |
| 1374 | newt.c_lflag &= ~(ICANON | ECHO); |
| 1375 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); |
| 1376 | ch = getchar(); |
| 1377 | return ch; |
| 1378 | } |
| 1379 | #else |
| 1380 | //Support RTOS inside Windows |
| 1381 | #undef kbhit |
| 1382 | #undef getch |
| 1383 | #undef putch |
| 1384 | extern int kbhit(); |
| 1385 | extern int getch(void); |
| 1386 | extern int putch(int); |
| 1387 | extern void __stdcall Sleep(unsigned long value); |
| 1388 | #endif |
| 1389 | |
| 1390 | static uint32 Memory[8]; |
| 1391 | |
| 1392 | uint32 MemoryRead(uint32 address) |
| 1393 | { |
| 1394 | Memory[2] |= IRQ_UART_WRITE_AVAILABLE; //IRQ_STATUS |
| 1395 | switch(address) |
| 1396 | { |
| 1397 | case UART_READ: |
| 1398 | if(kbhit()) |
| 1399 | Memory[0] = getch(); //UART_READ |
| 1400 | Memory[2] &= ~IRQ_UART_READ_AVAILABLE; //clear bit |
| 1401 | return Memory[0]; |
| 1402 | case IRQ_MASK: |
| 1403 | return Memory[1]; //IRQ_MASK |
| 1404 | case IRQ_MASK + 4: |
| 1405 | Sleep(10); |
| 1406 | return 0; |
| 1407 | case IRQ_STATUS: |
| 1408 | if(kbhit()) |
| 1409 | Memory[2] |= IRQ_UART_READ_AVAILABLE; |
| 1410 | return Memory[2]; |
| 1411 | } |
| 1412 | return 0; |
| 1413 | } |
| 1414 | |
| 1415 | void MemoryWrite(uint32 address, uint32 value) |
| 1416 | { |
| 1417 | switch(address) |
| 1418 | { |
| 1419 | case UART_WRITE: |
| 1420 | putch(value); |
| 1421 | break; |
| 1422 | case IRQ_MASK: |
| 1423 | Memory[1] = value; |
| 1424 | break; |
| 1425 | case IRQ_STATUS: |
| 1426 | Memory[2] = value; |
| 1427 | break; |
| 1428 | } |
| 1429 | } |
| 1430 | |
| 1431 | uint32 OS_AsmInterruptEnable(uint32 enableInterrupt) |
| 1432 | { |
| 1433 | return enableInterrupt; |
| 1434 | } |
| 1435 | |
| 1436 | void OS_AsmInterruptInit(void) |
| 1437 | { |
| 1438 | } |
| 1439 | #endif //WIN32 |
| 1440 | |
| 1441 | |
| 1442 | /**************** Example *****************/ |
| 1443 | #ifndef NO_MAIN |
| 1444 | #ifdef WIN32 |
| 1445 | static uint8 HeapSpace[1024*512]; |
| 1446 | #endif |
| 1447 | |
| 1448 | int main(int programEnd, char *argv[]) |
| 1449 | { |
| 1450 | (void)programEnd; //Pointer to end of used memory |
| 1451 | (void)argv; |
| 1452 | |
| 1453 | UartPrintfCritical("Starting RTOS\n"); |
| 1454 | #ifdef WIN32 |
| 1455 | OS_Init((uint32*)HeapSpace, sizeof(HeapSpace)); |
| 1456 | #else |
| 1457 | //Remaining space after program in 1MB external RAM |
| 1458 | OS_Init((uint32*)programEnd, |
| 1459 | RAM_EXTERNAL_BASE + RAM_EXTERNAL_SIZE - programEnd); |
| 1460 | #endif |
| 1461 | UartInit(); |
| 1462 | OS_ThreadCreate("Main", MainThread, NULL, 100, 4000); |
| 1463 | OS_Start(); |
| 1464 | return 0; |
| 1465 | } |
| 1466 | #endif //NO_MAIN |
| 1467 | |
plasma/kernel/rtos.h |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma Real Time Operating System |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 12/17/05 |
| 5 | * FILENAME: rtos.h |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma Real Time Operating System |
| 11 | *--------------------------------------------------------------------*/ |
| 12 | #ifndef __RTOS_H__ |
| 13 | #define __RTOS_H__ |
| 14 | |
| 15 | // Symmetric Multi-Processing |
| 16 | #define OS_CPU_COUNT 1 |
| 17 | |
| 18 | // Typedefs |
| 19 | typedef unsigned int uint32; |
| 20 | typedef unsigned short uint16; |
| 21 | typedef unsigned char uint8; |
| 22 | |
| 23 | // Memory Access |
| 24 | #ifdef WIN32 |
| 25 | uint32 MemoryRead(uint32 Address); |
| 26 | void MemoryWrite(uint32 Address, uint32 Value); |
| 27 | #else |
| 28 | #define MemoryRead(A) (*(volatile uint32*)(A)) |
| 29 | #define MemoryWrite(A,V) *(volatile uint32*)(A)=(V) |
| 30 | #endif |
| 31 | |
| 32 | /***************** LibC ******************/ |
| 33 | #if !defined(_LIBC) && !defined(_CTYPE_DEFINED) |
| 34 | #define printf UartPrintf |
| 35 | //#define printf UartPrintfPoll |
| 36 | #define scanf UartScanf |
| 37 | #ifndef WIN32 |
| 38 | #define malloc(S) OS_HeapMalloc(NULL, S) |
| 39 | #define free(S) OS_HeapFree(S) |
| 40 | #endif |
| 41 | |
| 42 | #ifndef NULL |
| 43 | #define NULL (void*)0 |
| 44 | #endif |
| 45 | |
| 46 | #define assert(A) if((A)==0){OS_Assert();UartPrintfCritical("\r\nAssert %s:%d\r\n", __FILE__, __LINE__);} |
| 47 | |
| 48 | #define isprint(c) (' '<=(c)&&(c)<='~') |
| 49 | #define isspace(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)=='\r') |
| 50 | #define isdigit(c) ('0'<=(c)&&(c)<='9') |
| 51 | #define islower(c) ('a'<=(c)&&(c)<='z') |
| 52 | #define isupper(c) ('A'<=(c)&&(c)<='Z') |
| 53 | #define isalpha(c) (islower(c)||isupper(c)) |
| 54 | #define isalnum(c) (isalpha(c)||isdigit(c)) |
| 55 | #undef min |
| 56 | #define min(a,b) ((a)<(b)?(a):(b)) |
| 57 | #define strcpy strcpy2 //don't use intrinsic functions |
| 58 | #define strcat strcat2 |
| 59 | #define strncat strncat2 |
| 60 | #define strcmp strcmp2 |
| 61 | #define strlen strlen2 |
| 62 | #define memcpy memcpy2 |
| 63 | #define memcmp memcmp2 |
| 64 | #define memset memset2 |
| 65 | #define abs abs2 |
| 66 | #define atoi atoi2 |
| 67 | |
| 68 | char *strcpy(char *dst, const char *src); |
| 69 | char *strncpy(char *dst, const char *src, int count); |
| 70 | char *strcat(char *dst, const char *src); |
| 71 | char *strncat(char *dst, const char *src, int count); |
| 72 | int strcmp(const char *string1, const char *string2); |
| 73 | int strncmp(const char *string1, const char *string2, int count); |
| 74 | char *strstr(const char *string, const char *find); |
| 75 | int strlen(const char *string); |
| 76 | void *memcpy(void *dst, const void *src, unsigned long bytes); |
| 77 | void *memmove(void *dst, const void *src, unsigned long bytes); |
| 78 | int memcmp(const void *cs, const void *ct, unsigned long bytes); |
| 79 | void *memset(void *dst, int c, unsigned long bytes); |
| 80 | int abs(int n); |
| 81 | int rand(void); |
| 82 | void srand(unsigned int seed); |
| 83 | long strtol(const char *s, char **end, int base); |
| 84 | int atoi(const char *s); |
| 85 | char *itoa(int num, char *dst, int base); |
| 86 | #ifndef NO_ELLIPSIS |
| 87 | int sprintf(char *s, const char *format, ...); |
| 88 | int sscanf(const char *s, const char *format, ...); |
| 89 | #endif |
| 90 | #ifdef INCLUDE_DUMP |
| 91 | void dump(const unsigned char *data, int length); |
| 92 | #endif |
| 93 | #ifdef INCLUDE_QSORT |
| 94 | void qsort(void *base, |
| 95 | long n, |
| 96 | long size, |
| 97 | int (*cmp)(const void *,const void *)); |
| 98 | void *bsearch(const void *key, |
| 99 | const void *base, |
| 100 | long n, |
| 101 | long size, |
| 102 | int (*cmp)(const void *,const void *)); |
| 103 | #endif |
| 104 | #ifdef INCLUDE_TIMELIB |
| 105 | #define difftime(time2,time1) (time2-time1) |
| 106 | typedef unsigned long time_t; //start at 1/1/80 |
| 107 | struct tm { |
| 108 | int tm_sec; //(0,59) |
| 109 | int tm_min; //(0,59) |
| 110 | int tm_hour; //(0,23) |
| 111 | int tm_mday; //(1,31) |
| 112 | int tm_mon; //(0,11) |
| 113 | int tm_year; //(0,n) from 1900 |
| 114 | int tm_wday; //(0,6) calculated |
| 115 | int tm_yday; //(0,365) calculated |
| 116 | int tm_isdst; // calculated |
| 117 | }; |
| 118 | time_t mktime(struct tm *tp); |
| 119 | void gmtime_r(const time_t *tp, struct tm *out); |
| 120 | void gmtimeDst(time_t dstTimeIn, time_t dstTimeOut); |
| 121 | void gmtimeDstSet(time_t *tp, time_t *dstTimeIn, time_t *dstTimeOut); |
| 122 | #endif |
| 123 | #define _LIBC |
| 124 | #endif //_LIBC |
| 125 | |
| 126 | /***************** Assembly **************/ |
| 127 | typedef uint32 jmp_buf[20]; |
| 128 | extern uint32 OS_AsmInterruptEnable(uint32 state); |
| 129 | extern void OS_AsmInterruptInit(void); |
| 130 | extern int setjmp(jmp_buf env); |
| 131 | extern void longjmp(jmp_buf env, int val); |
| 132 | extern uint32 OS_AsmMult(uint32 a, uint32 b, unsigned long *hi); |
| 133 | extern void *OS_Syscall(); |
| 134 | |
| 135 | /***************** Heap ******************/ |
| 136 | #define HEAP_USER (void*)0 |
| 137 | #define HEAP_SYSTEM (void*)1 |
| 138 | #define HEAP_SMALL (void*)2 |
| 139 | #define HEAP_UI (void*)3 |
| 140 | typedef struct OS_Heap_s OS_Heap_t; |
| 141 | OS_Heap_t *OS_HeapCreate(const char *name, void *memory, uint32 size); |
| 142 | void OS_HeapDestroy(OS_Heap_t *heap); |
| 143 | void *OS_HeapMalloc(OS_Heap_t *heap, int bytes); |
| 144 | void OS_HeapFree(void *block); |
| 145 | void OS_HeapAlternate(OS_Heap_t *heap, OS_Heap_t *alternate); |
| 146 | void OS_HeapRegister(void *index, OS_Heap_t *heap); |
| 147 | |
| 148 | /***************** Critical Sections *****************/ |
| 149 | #if OS_CPU_COUNT <= 1 |
| 150 | // Single CPU |
| 151 | #define OS_CpuIndex() 0 |
| 152 | #define OS_CriticalBegin() OS_AsmInterruptEnable(0) |
| 153 | #define OS_CriticalEnd(S) OS_AsmInterruptEnable(S) |
| 154 | #define OS_SpinLock() 0 |
| 155 | #define OS_SpinUnlock(S) |
| 156 | #else |
| 157 | // Symmetric multiprocessing |
| 158 | uint32 OS_CpuIndex(void); |
| 159 | #define OS_CriticalBegin() OS_SpinLock() |
| 160 | #define OS_CriticalEnd(S) OS_SpinUnlock(S) |
| 161 | uint32 OS_SpinLock(void); |
| 162 | void OS_SpinUnlock(uint32 state); |
| 163 | #endif |
| 164 | |
| 165 | /***************** Thread *****************/ |
| 166 | #ifdef WIN32 |
| 167 | #define STACK_SIZE_MINIMUM (1024*4) |
| 168 | #else |
| 169 | #define STACK_SIZE_MINIMUM (1024*1) |
| 170 | #endif |
| 171 | #define STACK_SIZE_DEFAULT 1024*2 |
| 172 | #undef THREAD_PRIORITY_IDLE |
| 173 | #define THREAD_PRIORITY_IDLE 0 |
| 174 | #define THREAD_PRIORITY_MAX 255 |
| 175 | |
| 176 | typedef void (*OS_FuncPtr_t)(void *arg); |
| 177 | typedef struct OS_Thread_s OS_Thread_t; |
| 178 | OS_Thread_t *OS_ThreadCreate(const char *name, |
| 179 | OS_FuncPtr_t funcPtr, |
| 180 | void *arg, |
| 181 | uint32 priority, |
| 182 | uint32 stackSize); |
| 183 | void OS_ThreadExit(void); |
| 184 | OS_Thread_t *OS_ThreadSelf(void); |
| 185 | void OS_ThreadSleep(int ticks); |
| 186 | uint32 OS_ThreadTime(void); |
| 187 | void OS_ThreadInfoSet(OS_Thread_t *thread, uint32 index, void *info); |
| 188 | void *OS_ThreadInfoGet(OS_Thread_t *thread, uint32 index); |
| 189 | uint32 OS_ThreadPriorityGet(OS_Thread_t *thread); |
| 190 | void OS_ThreadPrioritySet(OS_Thread_t *thread, uint32 priority); |
| 191 | void OS_ThreadProcessId(OS_Thread_t *thread, uint32 processId, OS_Heap_t *heap); |
| 192 | void OS_ThreadTick(void *arg); |
| 193 | void OS_ThreadCpuLock(OS_Thread_t *thread, int cpuIndex); |
| 194 | |
| 195 | /***************** Semaphore **************/ |
| 196 | #define OS_SUCCESS 0 |
| 197 | #define OS_ERROR -1 |
| 198 | #define OS_WAIT_FOREVER -1 |
| 199 | #define OS_NO_WAIT 0 |
| 200 | typedef struct OS_Semaphore_s OS_Semaphore_t; |
| 201 | OS_Semaphore_t *OS_SemaphoreCreate(const char *name, uint32 count); |
| 202 | void OS_SemaphoreDelete(OS_Semaphore_t *semaphore); |
| 203 | int OS_SemaphorePend(OS_Semaphore_t *semaphore, int ticks); //tick ~= 10ms |
| 204 | void OS_SemaphorePost(OS_Semaphore_t *semaphore); |
| 205 | |
| 206 | /***************** Mutex ******************/ |
| 207 | typedef struct OS_Mutex_s OS_Mutex_t; |
| 208 | OS_Mutex_t *OS_MutexCreate(const char *name); |
| 209 | void OS_MutexDelete(OS_Mutex_t *semaphore); |
| 210 | void OS_MutexPend(OS_Mutex_t *semaphore); |
| 211 | void OS_MutexPost(OS_Mutex_t *semaphore); |
| 212 | |
| 213 | /***************** MQueue *****************/ |
| 214 | enum { |
| 215 | MESSAGE_TYPE_USER = 0, |
| 216 | MESSAGE_TYPE_TIMER = 5 |
| 217 | }; |
| 218 | typedef struct OS_MQueue_s OS_MQueue_t; |
| 219 | OS_MQueue_t *OS_MQueueCreate(const char *name, |
| 220 | int messageCount, |
| 221 | int messageBytes); |
| 222 | void OS_MQueueDelete(OS_MQueue_t *mQueue); |
| 223 | int OS_MQueueSend(OS_MQueue_t *mQueue, void *message); |
| 224 | int OS_MQueueGet(OS_MQueue_t *mQueue, void *message, int ticks); |
| 225 | |
| 226 | /***************** Job ********************/ |
| 227 | void OS_Job(void (*funcPtr)(), void *arg0, void *arg1, void *arg2); |
| 228 | |
| 229 | /***************** Timer ******************/ |
| 230 | typedef struct OS_Timer_s OS_Timer_t; |
| 231 | typedef void (*OS_TimerFuncPtr_t)(OS_Timer_t *timer, uint32 info); |
| 232 | OS_Timer_t *OS_TimerCreate(const char *name, OS_MQueue_t *mQueue, uint32 info); |
| 233 | void OS_TimerDelete(OS_Timer_t *timer); |
| 234 | void OS_TimerCallback(OS_Timer_t *timer, OS_TimerFuncPtr_t callback); |
| 235 | void OS_TimerStart(OS_Timer_t *timer, uint32 ticks, uint32 ticksRestart); |
| 236 | void OS_TimerStop(OS_Timer_t *timer); |
| 237 | |
| 238 | /***************** ISR ********************/ |
| 239 | #define STACK_EPC 88/4 |
| 240 | void OS_InterruptServiceRoutine(uint32 status, uint32 *stack); |
| 241 | void OS_InterruptRegister(uint32 mask, OS_FuncPtr_t funcPtr); |
| 242 | uint32 OS_InterruptStatus(void); |
| 243 | uint32 OS_InterruptMaskSet(uint32 mask); |
| 244 | uint32 OS_InterruptMaskClear(uint32 mask); |
| 245 | |
| 246 | /***************** Init ******************/ |
| 247 | void OS_Init(uint32 *heapStorage, uint32 bytes); |
| 248 | void OS_Start(void); |
| 249 | void OS_Assert(void); |
| 250 | void OS_DebuggerInit(void); |
| 251 | void MainThread(void *Arg); |
| 252 | |
| 253 | /***************** MMU ******************/ |
| 254 | typedef struct { |
| 255 | const char *name; |
| 256 | OS_FuncPtr_t funcPtr; |
| 257 | void *arg; |
| 258 | uint32 priority; |
| 259 | uint32 stackSize; |
| 260 | uint32 heapSize; |
| 261 | uint32 processId; |
| 262 | OS_Semaphore_t *semaphoreDone; |
| 263 | uint8 *memory; //private |
| 264 | OS_Heap_t *heap; //private |
| 265 | OS_Thread_t *thread; //private |
| 266 | } OS_Process_t; |
| 267 | void OS_MMUInit(void); |
| 268 | void OS_MMUMemoryRegister(uint32 processId, |
| 269 | uint32 virtualAddress, |
| 270 | uint32 physicalAddress, |
| 271 | uint32 size, |
| 272 | uint32 writable); |
| 273 | OS_Process_t *OS_MMUProcessCreate(OS_Process_t *process); |
| 274 | void OS_MMUProcessDelete(OS_Process_t *process); |
| 275 | void OS_MMUUartPrintf(); |
| 276 | void OS_MMUUartScanf(); |
| 277 | void OS_MMUUartPrintfCritical(); |
| 278 | |
| 279 | /***************** UART ******************/ |
| 280 | typedef uint8* (*PacketGetFunc_t)(void); |
| 281 | void UartInit(void); |
| 282 | void UartWrite(int ch); |
| 283 | uint8 UartRead(void); |
| 284 | void UartWriteData(uint8 *data, int length); |
| 285 | void UartReadData(uint8 *data, int length); |
| 286 | #ifndef NO_ELLIPSIS2 |
| 287 | void UartPrintf(const char *format, ...); |
| 288 | void UartPrintfPoll(const char *format, ...); |
| 289 | void UartPrintfCritical(const char *format, ...); |
| 290 | void UartPrintfNull(const char *format, ...); |
| 291 | void UartScanf(const char *format, ...); |
| 292 | #endif |
| 293 | void UartPacketConfig(PacketGetFunc_t packetGetFunc, |
| 294 | int packetSize, |
| 295 | OS_MQueue_t *mQueue); |
| 296 | void UartPacketSend(uint8 *data, int bytes); |
| 297 | #ifdef WIN32 |
| 298 | #define puts puts2 |
| 299 | #define getch getch2 |
| 300 | #define kbhit kbhit2 |
| 301 | #endif |
| 302 | int puts(const char *string); |
| 303 | int getch(void); |
| 304 | int kbhit(void); |
| 305 | void LogWrite(int a); |
| 306 | void LogDump(void); |
| 307 | void Led(int mask, int value); |
| 308 | |
| 309 | /***************** Keyboard **************/ |
| 310 | #define KEYBOARD_RAW 0x100 |
| 311 | #define KEYBOARD_E0 0x200 |
| 312 | #define KEYBOARD_RELEASE 0x400 |
| 313 | void KeyboardInit(void); |
| 314 | int KeyboardGetch(void); |
| 315 | |
| 316 | /***************** Math ******************/ |
| 317 | //IEEE single precision floating point math |
| 318 | #ifndef WIN32 |
| 319 | #define FP_Neg __negsf2 |
| 320 | #define FP_Add __addsf3 |
| 321 | #define FP_Sub __subsf3 |
| 322 | #define FP_Mult __mulsf3 |
| 323 | #define FP_Div __divsf3 |
| 324 | #define FP_ToLong __fixsfsi |
| 325 | #define FP_ToFloat __floatsisf |
| 326 | #define sqrt FP_Sqrt |
| 327 | #define cos FP_Cos |
| 328 | #define sin FP_Sin |
| 329 | #define atan FP_Atan |
| 330 | #define log FP_Log |
| 331 | #define exp FP_Exp |
| 332 | #endif |
| 333 | float FP_Neg(float a_fp); |
| 334 | float FP_Add(float a_fp, float b_fp); |
| 335 | float FP_Sub(float a_fp, float b_fp); |
| 336 | float FP_Mult(float a_fp, float b_fp); |
| 337 | float FP_Div(float a_fp, float b_fp); |
| 338 | long FP_ToLong(float a_fp); |
| 339 | float FP_ToFloat(long af); |
| 340 | int FP_Cmp(float a_fp, float b_fp); |
| 341 | float FP_Sqrt(float a); |
| 342 | float FP_Cos(float rad); |
| 343 | float FP_Sin(float rad); |
| 344 | float FP_Atan(float x); |
| 345 | float FP_Atan2(float y, float x); |
| 346 | float FP_Exp(float x); |
| 347 | float FP_Log(float x); |
| 348 | float FP_Pow(float x, float y); |
| 349 | |
| 350 | /***************** Filesys ******************/ |
| 351 | #ifdef INCLUDE_FILESYS |
| 352 | #define FILE OS_FILE |
| 353 | #define fopen OS_fopen |
| 354 | #define fclose OS_fclose |
| 355 | #define fread OS_fread |
| 356 | #define fwrite OS_fwrite |
| 357 | #define fseek OS_fseek |
| 358 | #endif |
| 359 | #define _FILESYS_ |
| 360 | typedef struct OS_FILE_s OS_FILE; |
| 361 | OS_FILE *OS_fopen(char *name, char *mode); |
| 362 | void OS_fclose(OS_FILE *file); |
| 363 | int OS_fread(void *buffer, int size, int count, OS_FILE *file); |
| 364 | int OS_fwrite(void *buffer, int size, int count, OS_FILE *file); |
| 365 | int OS_fseek(OS_FILE *file, int offset, int mode); |
| 366 | int OS_fmkdir(char *name); |
| 367 | int OS_fdir(OS_FILE *dir, char name[64]); |
| 368 | void OS_fdelete(char *name); |
| 369 | int OS_flength(char *entry); |
| 370 | |
| 371 | /***************** Flash ******************/ |
| 372 | void FlashRead(uint16 *dst, uint32 byteOffset, int bytes); |
| 373 | void FlashWrite(uint16 *src, uint32 byteOffset, int bytes); |
| 374 | void FlashErase(uint32 byteOffset); |
| 375 | |
| 376 | #endif //__RTOS_H__ |
| 377 | |
plasma/kernel/rtos_test.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Test Plasma Real Time Operating System |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 1/1/06 |
| 5 | * FILENAME: rtos_test.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Test Plasma Real Time Operating System |
| 11 | *--------------------------------------------------------------------*/ |
| 12 | #include "plasma.h" |
| 13 | #include "rtos.h" |
| 14 | #include "tcpip.h" |
| 15 | |
| 16 | /* Including mmu.h will cause all OS calls to use SYSCALL */ |
| 17 | //#include "mmu.h" |
| 18 | |
| 19 | //#define DLL_SETUP |
| 20 | //#define DLL_CALL |
| 21 | //#include "dll.h" |
| 22 | |
| 23 | #define SEMAPHORE_COUNT 50 |
| 24 | #define TIMER_COUNT 10 |
| 25 | |
| 26 | extern void TestMathFull(void); |
| 27 | |
| 28 | typedef struct { |
| 29 | OS_Thread_t *MyThread[TIMER_COUNT]; |
| 30 | OS_Semaphore_t *MySemaphore[SEMAPHORE_COUNT]; |
| 31 | OS_Mutex_t *MyMutex; |
| 32 | OS_Timer_t *MyTimer[TIMER_COUNT]; |
| 33 | OS_MQueue_t *MyQueue[TIMER_COUNT]; |
| 34 | int TimerDone; |
| 35 | } TestInfo_t; |
| 36 | |
| 37 | int Global; |
| 38 | |
| 39 | //****************************************************************** |
| 40 | static void TestCLib(void) |
| 41 | { |
| 42 | char s1[80], s2[80], *ptr; |
| 43 | int rc, v1, v2, v3; |
| 44 | |
| 45 | printf("TestCLib\n"); |
| 46 | strcpy(s1, "Hello "); |
| 47 | memset(s2, 0, sizeof(s2)); |
| 48 | strncpy(s2, "World wide", 5); |
| 49 | strcat(s1, s2); |
| 50 | strncat(s1, "!\nthing", 14); |
| 51 | printf("%s", s1); |
| 52 | rc = strcmp(s1, "Hello World!\n"); |
| 53 | assert(rc == 0); |
| 54 | rc = strcmp(s1, "Hello WOrld!\n"); |
| 55 | assert(rc > 0); |
| 56 | rc = strcmp(s1, "Hello world!\n"); |
| 57 | assert(rc < 0); |
| 58 | rc = strncmp(s1, "Hellx", 4); |
| 59 | assert(rc == 0); |
| 60 | ptr = strstr(s1, "orl"); |
| 61 | assert(ptr[0] = 'o'); |
| 62 | rc = strlen(s1); |
| 63 | assert(rc == 13); |
| 64 | memcpy(s2, s1, rc+1); |
| 65 | rc = memcmp(s1, s2, 8); |
| 66 | assert(rc == 0); |
| 67 | s2[5] = 'z'; |
| 68 | rc = memcmp(s1, s2, 8); |
| 69 | assert(rc != 0); |
| 70 | memset(s2, 0, 5); |
| 71 | memset(s2, 'a', 3); |
| 72 | rc = abs(-5); |
| 73 | itoa(1234, s1, 10); |
| 74 | itoa(0, s1, 10); |
| 75 | itoa(-1234, s1, 10); |
| 76 | itoa(0xabcd, s1, 16); |
| 77 | itoa(0x12ab, s1, 16); |
| 78 | sprintf(s1, "test c%c d%d 0x%x s%s End\n", 'C', 1234, 0xabcd, "String"); |
| 79 | printf("%s", s1); |
| 80 | sprintf(s1, "test c%c d%6d 0x%6x s%8s End\n", 'C', 1234, 0xabcd, "String"); |
| 81 | printf("%s", s1); |
| 82 | sscanf("1234 -1234 0xabcd text h", "%d %d %x %s", &v1, &v2, &v3, s1); |
| 83 | assert(v1 == 1234 && v2 == -1234 && v3 == 0xabcd); |
| 84 | assert(strcmp(s1, "text") == 0); |
| 85 | //UartScanf("%d %d", &v1, &v2); |
| 86 | //printf("v1 = %d v2 = %d\n", v1, v2); |
| 87 | printf("Done.\n"); |
| 88 | } |
| 89 | |
| 90 | //****************************************************************** |
| 91 | static void TestHeap(void) |
| 92 | { |
| 93 | uint8 *ptrs[256], size[256], *ptr; |
| 94 | int i, j, k, value; |
| 95 | |
| 96 | printf("TestHeap\n"); |
| 97 | memset(ptrs, 0, sizeof(ptrs)); |
| 98 | for(i = 0; i < 1000; ++i) |
| 99 | { |
| 100 | j = rand() & 255; |
| 101 | if(ptrs[j]) |
| 102 | { |
| 103 | ptr = ptrs[j]; |
| 104 | value = size[j]; |
| 105 | for(k = 0; k < value; ++k) |
| 106 | { |
| 107 | if(ptr[k] != value) |
| 108 | printf("Error\n"); |
| 109 | } |
| 110 | OS_HeapFree(ptrs[j]); |
| 111 | } |
| 112 | size[j] = (uint8)(rand() & 255); |
| 113 | ptrs[j] = OS_HeapMalloc(NULL, size[j]); |
| 114 | if(ptrs[j] == NULL) |
| 115 | printf("malloc NULL\n"); |
| 116 | else |
| 117 | memset(ptrs[j], size[j], size[j]); |
| 118 | } |
| 119 | for(i = 0; i < 256; ++i) |
| 120 | { |
| 121 | if(ptrs[i]) |
| 122 | OS_HeapFree(ptrs[i]); |
| 123 | } |
| 124 | printf("Done.\n"); |
| 125 | } |
| 126 | |
| 127 | //****************************************************************** |
| 128 | static void MyThreadMain(void *arg) |
| 129 | { |
| 130 | OS_Thread_t *thread; |
| 131 | int priority; |
| 132 | |
| 133 | thread = OS_ThreadSelf(); |
| 134 | priority = OS_ThreadPriorityGet(thread); |
| 135 | OS_ThreadSleep(10); |
| 136 | printf("Arg=%d thread=0x%x info=0x%x priority=%d\n", |
| 137 | (uint32)arg, thread, OS_ThreadInfoGet(thread, 0), priority); |
| 138 | OS_ThreadExit(); |
| 139 | } |
| 140 | |
| 141 | static void TestThread(void) |
| 142 | { |
| 143 | OS_Thread_t *thread; |
| 144 | int i, priority; |
| 145 | |
| 146 | printf("TestThread\n"); |
| 147 | for(i = 0; i < 32; ++i) |
| 148 | { |
| 149 | priority = 50 + i; |
| 150 | thread = OS_ThreadCreate("MyThread", MyThreadMain, (uint32*)i, priority, 0); |
| 151 | OS_ThreadInfoSet(thread, 0, (void*)(0xabcd + i)); |
| 152 | //printf("Created thread 0x%x\n", thread); |
| 153 | } |
| 154 | |
| 155 | thread = OS_ThreadSelf(); |
| 156 | priority = OS_ThreadPriorityGet(thread); |
| 157 | printf("Priority = %d\n", priority); |
| 158 | OS_ThreadPrioritySet(thread, 200); |
| 159 | printf("Priority = %d\n", OS_ThreadPriorityGet(thread)); |
| 160 | OS_ThreadPrioritySet(thread, priority); |
| 161 | |
| 162 | printf("Thread time = %d\n", OS_ThreadTime()); |
| 163 | OS_ThreadSleep(100); |
| 164 | printf("Thread time = %d\n", OS_ThreadTime()); |
| 165 | } |
| 166 | |
| 167 | //****************************************************************** |
| 168 | static void TestSemThread(void *arg) |
| 169 | { |
| 170 | int i; |
| 171 | TestInfo_t *info = (TestInfo_t*)arg; |
| 172 | |
| 173 | for(i = 0; i < SEMAPHORE_COUNT/2; ++i) |
| 174 | { |
| 175 | printf("s"); |
| 176 | OS_SemaphorePend(info->MySemaphore[i], OS_WAIT_FOREVER); |
| 177 | OS_SemaphorePost(info->MySemaphore[i + SEMAPHORE_COUNT/2]); |
| 178 | } |
| 179 | OS_ThreadExit(); |
| 180 | } |
| 181 | |
| 182 | static void TestSemaphore(void) |
| 183 | { |
| 184 | int i, rc; |
| 185 | TestInfo_t info; |
| 186 | printf("TestSemaphore\n"); |
| 187 | for(i = 0; i < SEMAPHORE_COUNT; ++i) |
| 188 | { |
| 189 | info.MySemaphore[i] = OS_SemaphoreCreate("MySem", 0); |
| 190 | //printf("sem[%d]=0x%x\n", i, MySemaphore[i]); |
| 191 | } |
| 192 | |
| 193 | OS_ThreadCreate("TestSem", TestSemThread, &info, 50, 0); |
| 194 | |
| 195 | for(i = 0; i < SEMAPHORE_COUNT/2; ++i) |
| 196 | { |
| 197 | printf("S"); |
| 198 | OS_SemaphorePost(info.MySemaphore[i]); |
| 199 | rc = OS_SemaphorePend(info.MySemaphore[i + SEMAPHORE_COUNT/2], 500); |
| 200 | assert(rc == 0); |
| 201 | } |
| 202 | |
| 203 | printf(":"); |
| 204 | rc = OS_SemaphorePend(info.MySemaphore[0], 10); |
| 205 | assert(rc != 0); |
| 206 | printf(":"); |
| 207 | OS_SemaphorePend(info.MySemaphore[0], 100); |
| 208 | printf(":"); |
| 209 | |
| 210 | for(i = 0; i < SEMAPHORE_COUNT; ++i) |
| 211 | OS_SemaphoreDelete(info.MySemaphore[i]); |
| 212 | |
| 213 | printf("\nDone.\n"); |
| 214 | } |
| 215 | |
| 216 | //****************************************************************** |
| 217 | static void TestMutexThread(void *arg) |
| 218 | { |
| 219 | TestInfo_t *info = (TestInfo_t*)arg; |
| 220 | |
| 221 | printf("Waiting for mutex\n"); |
| 222 | OS_MutexPend(info->MyMutex); |
| 223 | printf("Have Mutex1\n"); |
| 224 | OS_MutexPend(info->MyMutex); |
| 225 | printf("Have Mutex2\n"); |
| 226 | OS_MutexPend(info->MyMutex); |
| 227 | printf("Have Mutex3\n"); |
| 228 | |
| 229 | OS_ThreadSleep(100); |
| 230 | |
| 231 | OS_MutexPost(info->MyMutex); |
| 232 | OS_MutexPost(info->MyMutex); |
| 233 | OS_MutexPost(info->MyMutex); |
| 234 | |
| 235 | OS_ThreadExit(); |
| 236 | } |
| 237 | |
| 238 | static void TestMutex(void) |
| 239 | { |
| 240 | TestInfo_t info; |
| 241 | printf("TestMutex\n"); |
| 242 | info.MyMutex = OS_MutexCreate("MyMutex"); |
| 243 | OS_MutexPend(info.MyMutex); |
| 244 | OS_MutexPend(info.MyMutex); |
| 245 | OS_MutexPend(info.MyMutex); |
| 246 | |
| 247 | OS_ThreadSleep(100); |
| 248 | |
| 249 | OS_ThreadCreate("TestMutex", TestMutexThread, &info, 50, 0); |
| 250 | |
| 251 | OS_ThreadSleep(50); |
| 252 | OS_MutexPost(info.MyMutex); |
| 253 | OS_MutexPost(info.MyMutex); |
| 254 | OS_MutexPost(info.MyMutex); |
| 255 | |
| 256 | printf("Try get mutex\n"); |
| 257 | OS_MutexPend(info.MyMutex); |
| 258 | printf("Gotit\n"); |
| 259 | |
| 260 | OS_MutexDelete(info.MyMutex); |
| 261 | printf("Done.\n"); |
| 262 | } |
| 263 | |
| 264 | //****************************************************************** |
| 265 | static void TestMQueue(void) |
| 266 | { |
| 267 | OS_MQueue_t *mqueue; |
| 268 | char data[16]; |
| 269 | int i, rc; |
| 270 | |
| 271 | printf("TestMQueue\n"); |
| 272 | mqueue = OS_MQueueCreate("MyMQueue", 10, 16); |
| 273 | strcpy(data, "Test0"); |
| 274 | for(i = 0; i < 16; ++i) |
| 275 | { |
| 276 | data[4] = (char)('0' + i); |
| 277 | OS_MQueueSend(mqueue, data); |
| 278 | } |
| 279 | for(i = 0; i < 16; ++i) |
| 280 | { |
| 281 | memset(data, 0, sizeof(data)); |
| 282 | rc = OS_MQueueGet(mqueue, data, 20); |
| 283 | if(rc == 0) |
| 284 | printf("message=(%s)\n", data); |
| 285 | else |
| 286 | printf("timeout\n"); |
| 287 | } |
| 288 | |
| 289 | OS_MQueueDelete(mqueue); |
| 290 | printf("Done.\n"); |
| 291 | } |
| 292 | |
| 293 | //****************************************************************** |
| 294 | static void TestTimerThread(void *arg) |
| 295 | { |
| 296 | int index; |
| 297 | uint32 data[4]; |
| 298 | OS_Timer_t *timer; |
| 299 | TestInfo_t *info = (TestInfo_t*)arg; |
| 300 | |
| 301 | //printf("TestTimerThread\n"); |
| 302 | |
| 303 | OS_ThreadSleep(1); |
| 304 | index = (int)OS_ThreadInfoGet(OS_ThreadSelf(), 0); |
| 305 | //printf("index=%d\n", index); |
| 306 | OS_MQueueGet(info->MyQueue[index], data, 1000); |
| 307 | timer = (OS_Timer_t*)data[1]; |
| 308 | printf("%d ", data[2]); |
| 309 | OS_MQueueGet(info->MyQueue[index], data, 1000); |
| 310 | printf("%d ", data[2]); |
| 311 | ++info->TimerDone; |
| 312 | OS_ThreadExit(); |
| 313 | } |
| 314 | |
| 315 | static void TestTimer(void) |
| 316 | { |
| 317 | int i; |
| 318 | TestInfo_t info; |
| 319 | |
| 320 | printf("TestTimer\n"); |
| 321 | info.TimerDone = 0; |
| 322 | for(i = 0; i < TIMER_COUNT; ++i) |
| 323 | { |
| 324 | info.MyQueue[i] = OS_MQueueCreate("MyQueue", 10, 16); |
| 325 | info.MyTimer[i] = OS_TimerCreate("MyTimer", info.MyQueue[i], i); |
| 326 | info.MyThread[i] = OS_ThreadCreate("TimerTest", TestTimerThread, &info, 50, 0); |
| 327 | OS_ThreadInfoSet(info.MyThread[i], 0, (void*)i); |
| 328 | OS_TimerStart(info.MyTimer[i], 10+i*2, 220+i); |
| 329 | } |
| 330 | |
| 331 | while(info.TimerDone < TIMER_COUNT) |
| 332 | OS_ThreadSleep(10); |
| 333 | |
| 334 | for(i = 0; i < TIMER_COUNT; ++i) |
| 335 | { |
| 336 | OS_MQueueDelete(info.MyQueue[i]); |
| 337 | OS_TimerDelete(info.MyTimer[i]); |
| 338 | } |
| 339 | |
| 340 | printf("Done.\n"); |
| 341 | } |
| 342 | |
| 343 | //****************************************************************** |
| 344 | #if 1 |
| 345 | void TestMath(void) |
| 346 | { |
| 347 | int i; |
| 348 | float a, b, sum, diff, mult, div; |
| 349 | uint32 compare; |
| 350 | |
| 351 | //Check add subtract multiply and divide |
| 352 | for(i = -4; i < 4; ++i) |
| 353 | { |
| 354 | a = (float)(i * 10 + (float)63.2); |
| 355 | b = (float)(-i * 5 + (float)3.5); |
| 356 | sum = a + b; |
| 357 | diff = a - b; |
| 358 | mult = a * b; |
| 359 | div = a / b; |
| 360 | printf("a=%dE-3 b=%dE-3 sum=%dE-3 diff=%dE-3 mult=%dE-3 div=%dE-3\n", |
| 361 | (int)(a*(float)1000), (int)(b*(float)1000), |
| 362 | (int)(sum*(float)1000), (int)(diff*(float)1000), |
| 363 | (int)(mult*(float)1000), (int)(div*(float)1000)); |
| 364 | } |
| 365 | |
| 366 | //Comparisons |
| 367 | b = (float)2.0; |
| 368 | compare = 0; |
| 369 | for(i = 1; i < 4; ++i) |
| 370 | { |
| 371 | a = (float)i; |
| 372 | compare = (compare << 1) | (a == b); |
| 373 | compare = (compare << 1) | (a != b); |
| 374 | compare = (compare << 1) | (a < b); |
| 375 | compare = (compare << 1) | (a <= b); |
| 376 | compare = (compare << 1) | (a > b); |
| 377 | compare = (compare << 1) | (a >= b); |
| 378 | } |
| 379 | printf("Compare = %8x %s\n", compare, |
| 380 | compare==0x1c953 ? "OK" : "ERROR"); |
| 381 | |
| 382 | //Cosine |
| 383 | for(a = (float)0.0; a <= (float)(3.1415); a += (float)(3.1415/16.0)) |
| 384 | { |
| 385 | b = FP_Cos(a); |
| 386 | printf("cos(%4dE-3) = %4dE-3\n", |
| 387 | (int)(a*(float)1000.0), (int)(b*(float)1000.0)); |
| 388 | } |
| 389 | } |
| 390 | #endif |
| 391 | |
| 392 | //****************************************************************** |
| 393 | #ifndef WIN32 |
| 394 | static void MySyscall(void *arg) |
| 395 | { |
| 396 | uint32 *stack = arg; |
| 397 | stack[STACK_EPC] += 4; //skip over SYSCALL |
| 398 | printf("Inside MySyscall %d\n", stack[28/4]); |
| 399 | } |
| 400 | |
| 401 | void TestSyscall(void) |
| 402 | { |
| 403 | OS_InterruptRegister((uint32)(1<<31), MySyscall); |
| 404 | OS_Syscall(57); |
| 405 | OS_ThreadSleep(1); |
| 406 | printf("Done\n"); |
| 407 | } |
| 408 | #endif |
| 409 | |
| 410 | #ifdef __MMU_ENUM_H__ |
| 411 | void TestProcess(void) |
| 412 | { |
| 413 | OS_Process_t *process; |
| 414 | process = (OS_Process_t*)OS_HeapMalloc(NULL, sizeof(OS_Process_t)); |
| 415 | process->name = "test"; |
| 416 | process->funcPtr = MainThread; |
| 417 | process->arg = NULL; |
| 418 | process->priority = 200; |
| 419 | process->stackSize = 1024*32; |
| 420 | process->heapSize = 1024*128; |
| 421 | process->processId = 1; |
| 422 | process->semaphoreDone = OS_SemaphoreCreate("processDone", 0); |
| 423 | printf("Creating process\n"); |
| 424 | OS_MMUProcessCreate(process); |
| 425 | OS_SemaphorePend(process->semaphoreDone, OS_WAIT_FOREVER); |
| 426 | printf("Process done\n"); |
| 427 | OS_MMUProcessDelete(process); |
| 428 | } |
| 429 | #endif |
| 430 | |
| 431 | |
| 432 | //****************************************************************** |
| 433 | void MMUTest(void); |
| 434 | void HtmlThread(void *arg); |
| 435 | void ConsoleInit(void); |
| 436 | void exit(int); |
| 437 | uint8 macAddress[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4}; |
| 438 | |
| 439 | |
| 440 | void MainThread(void *Arg) |
| 441 | { |
| 442 | int ch, i, display=1; |
| 443 | (void)Arg; |
| 444 | #ifdef __MMU_ENUM_H__ |
| 445 | OS_MMUInit(); |
| 446 | #endif |
| 447 | |
| 448 | #ifdef INCLUDE_ETH |
| 449 | EthernetInit(macAddress); |
| 450 | IPInit(EthernetTransmit, macAddress, "plasma"); |
| 451 | HtmlInit(1); |
| 452 | #endif |
| 453 | |
| 454 | #ifdef INCLUDE_HTML |
| 455 | IPInit(NULL, macAddress, "plasma"); |
| 456 | HtmlInit(1); |
| 457 | #endif |
| 458 | |
| 459 | #ifdef INCLUDE_CONSOLE |
| 460 | ConsoleInit(); |
| 461 | #endif |
| 462 | |
| 463 | for(;;) |
| 464 | { |
| 465 | if(display) |
| 466 | { |
| 467 | printf("\n"); |
| 468 | printf("1 CLib\n"); |
| 469 | printf("2 Heap\n"); |
| 470 | printf("3 Thread\n"); |
| 471 | printf("4 Semaphore\n"); |
| 472 | printf("5 Mutex\n"); |
| 473 | printf("6 MQueue\n"); |
| 474 | printf("7 Timer\n"); |
| 475 | printf("8 Math\n"); |
| 476 | printf("9 Syscall\n"); |
| 477 | #ifdef __MMU_ENUM_H__ |
| 478 | printf("p MMU Process\n"); |
| 479 | #endif |
| 480 | } |
| 481 | printf("> "); |
| 482 | display = 1; |
| 483 | ch = UartRead(); |
| 484 | printf("%c\n", ch); |
| 485 | switch(ch) |
| 486 | { |
| 487 | #ifdef WIN32 |
| 488 | case '0': exit(0); |
| 489 | #endif |
| 490 | case '1': TestCLib(); break; |
| 491 | case '2': TestHeap(); break; |
| 492 | case '3': TestThread(); break; |
| 493 | case '4': TestSemaphore(); break; |
| 494 | case '5': TestMutex(); break; |
| 495 | case '6': TestMQueue(); break; |
| 496 | case '7': TestTimer(); break; |
| 497 | case '8': TestMath(); break; |
| 498 | #ifndef WIN32 |
| 499 | case '9': TestSyscall(); break; |
| 500 | #endif |
| 501 | #ifdef __MMU_ENUM_H__ |
| 502 | case 'p': TestProcess(); break; |
| 503 | #endif |
| 504 | #ifdef WIN32 |
| 505 | case 'm': TestMathFull(); break; |
| 506 | #endif |
| 507 | case 'g': printf("Global=%d\n", ++Global); break; |
| 508 | default: |
| 509 | printf("E"); |
| 510 | display = 0; |
| 511 | for(i = 0; i < 30; ++i) |
| 512 | { |
| 513 | while(kbhit()) |
| 514 | ch = UartRead(); |
| 515 | OS_ThreadSleep(1); |
| 516 | } |
| 517 | break; |
| 518 | } |
| 519 | } |
| 520 | } |
| 521 | |
| 522 | |
plasma/kernel/tcpip.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma TCP/IP Protocol Stack |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 4/22/06 |
| 5 | * FILENAME: tcpip.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma TCP/IP Protocol Stack |
| 11 | * |
| 12 | * Possible call stack when receiving a packet: |
| 13 | * IPMainThread() |
| 14 | * IPProcessEthernetPacket() |
| 15 | * IPProcessTCPPacket() |
| 16 | * TCPSendPacket() |
| 17 | * IPSendPacket() |
| 18 | * IPChecksum() |
| 19 | * IPSendFrame() |
| 20 | * FrameInsert() |
| 21 | *--------------------------------------------------------------------*/ |
| 22 | #ifdef WIN32 |
| 23 | #include <stdio.h> |
| 24 | #include <stdlib.h> |
| 25 | #include <string.h> |
| 26 | #include <assert.h> |
| 27 | #define _LIBC |
| 28 | #endif |
| 29 | #include "rtos.h" |
| 30 | #define IPPRINTF |
| 31 | #include "tcpip.h" |
| 32 | |
| 33 | |
| 34 | //ETHER FIELD OFFSET LENGTH VALUE |
| 35 | #define ETHERNET_DEST 0 //6 |
| 36 | #define ETHERNET_SOURCE 6 //6 |
| 37 | #define ETHERNET_FRAME_TYPE 12 //2 IP=0x0800; ARP=0x0806 |
| 38 | |
| 39 | //ARP FIELD OFFSET LENGTH VALUE |
| 40 | #define ARP_HARD_TYPE 14 //2 0x0001 |
| 41 | #define ARP_PROT_TYPE 16 //2 0x0800 |
| 42 | #define ARP_HARD_SIZE 18 //1 0x06 |
| 43 | #define ARP_PROT_SIZE 19 //1 0x04 |
| 44 | #define ARP_OP 20 //2 ARP=1;ARPreply=2 |
| 45 | #define ARP_ETHERNET_SENDER 22 //6 |
| 46 | #define ARP_IP_SENDER 28 //4 |
| 47 | #define ARP_ETHERNET_TARGET 32 //6 |
| 48 | #define ARP_IP_TARGET 38 //4 |
| 49 | #define ARP_PAD 42 //18 0 |
| 50 | |
| 51 | //IP FIELD OFFSET LENGTH VALUE |
| 52 | #define IP_VERSION_LENGTH 14 //1 0x45 |
| 53 | #define IP_TYPE_OF_SERVICE 15 //1 0x00 |
| 54 | #define IP_LENGTH 16 //2 |
| 55 | #define IP_ID16 18 //2 |
| 56 | #define IP_FRAG_OFFSET 20 //2 |
| 57 | #define IP_TIME_TO_LIVE 22 //1 0x80 |
| 58 | #define IP_PROTOCOL 23 //1 TCP=0x06;PING=0x01;UDP=0x11 |
| 59 | #define IP_CHECKSUM 24 //2 |
| 60 | #define IP_SOURCE 26 //4 |
| 61 | #define IP_DEST 30 //4 |
| 62 | |
| 63 | //PSEUDO FIELD OFFSET LENGTH VALUE |
| 64 | #define PSEUDO_IP_SOURCE 0 //4 |
| 65 | #define PSEUDO_IP_DEST 4 //4 |
| 66 | #define PSEUDO_ZERO 8 //1 0 |
| 67 | #define PSEUDO_IP_PROTOCOL 9 //1 |
| 68 | #define PSEUDO_LENGTH 10 //2 |
| 69 | |
| 70 | //UDP FIELD OFFSET LENGTH VALUE |
| 71 | #define UDP_SOURCE_PORT 34 //2 |
| 72 | #define UDP_DEST_PORT 36 //2 |
| 73 | #define UDP_LENGTH 38 //2 |
| 74 | #define UDP_CHECKSUM 40 //2 |
| 75 | #define UDP_DATA 42 |
| 76 | |
| 77 | //DHCP FIELD OFFSET LENGTH VALUE |
| 78 | #define DHCP_OPCODE 42 //1 REQUEST=1;REPLY=2 |
| 79 | #define DHCP_HW_TYPE 43 //1 1 |
| 80 | #define DHCP_HW_LEN 44 //1 6 |
| 81 | #define DHCP_HOP_COUNT 45 //1 0 |
| 82 | #define DHCP_TRANS_ID 46 //4 |
| 83 | #define DHCP_NUM_SEC 50 //2 0 |
| 84 | #define DHCP_UNUSED 52 //2 |
| 85 | #define DHCP_CLIENT_IP 54 //4 |
| 86 | #define DHCP_YOUR_IP 58 //4 |
| 87 | #define DHCP_SERVER_IP 62 //4 |
| 88 | #define DHCP_GATEWAY_IP 66 //4 |
| 89 | #define DHCP_CLIENT_ETHERNET 70 //16 |
| 90 | #define DHCP_SERVER_NAME 86 //64 |
| 91 | #define DHCP_BOOT_FILENAME 150 //128 |
| 92 | #define DHCP_MAGIC_COOKIE 278 //4 0x63825363 |
| 93 | #define DHCP_OPTIONS 282 //N |
| 94 | |
| 95 | #define DHCP_MESSAGE_TYPE 53 //1 type |
| 96 | #define DHCP_DISCOVER 1 |
| 97 | #define DHCP_OFFER 2 |
| 98 | #define DHCP_REQUEST 3 |
| 99 | #define DHCP_ACK 5 |
| 100 | #define DHCP_REQUEST_IP 50 //4 ip |
| 101 | #define DHCP_REQUEST_SERV_IP 54 //4 ip |
| 102 | #define DHCP_CLIENT_ID 61 //7 1 ethernet |
| 103 | #define DHCP_HOST_NAME 12 //6 plasma |
| 104 | #define DHCP_PARAMS 55 //4 1=subnet; 15=domain_name; 3=router; 6=dns |
| 105 | #define DHCP_PARAM_SUBNET 1 |
| 106 | #define DHCP_PARAM_ROUTER 3 |
| 107 | #define DHCP_PARAM_DNS 6 |
| 108 | #define DHCP_END_OPTION 0xff |
| 109 | |
| 110 | //DHCP FIELD OFFSET LENGTH VALUE |
| 111 | #define DNS_ID 0 //2 |
| 112 | #define DNS_FLAGS 2 //2 |
| 113 | #define DNS_NUM_QUESTIONS 4 //2 1 |
| 114 | #define DNS_NUM_ANSWERS_RR 6 //2 0/1 |
| 115 | #define DNS_NUM_AUTHORITY_RR 8 //2 0 |
| 116 | #define DNS_NUM_ADDITIONAL_RR 10 //2 0 |
| 117 | #define DNS_QUESTIONS 12 //2 |
| 118 | |
| 119 | #define DNS_FLAGS_RESPONSE 0x8000 |
| 120 | #define DNS_FLAGS_RECURSIVE 0x0100 |
| 121 | #define DNS_FLAGS_ERROR 0x0003 |
| 122 | #define DNS_FLAGS_OK 0x0000 |
| 123 | #define DNS_QUERY_TYPE_IP 1 |
| 124 | #define DNS_QUERY_CLASS 1 |
| 125 | #define DNS_PORT 53 |
| 126 | |
| 127 | //TCP FIELD OFFSET LENGTH VALUE |
| 128 | #define TCP_SOURCE_PORT 34 //2 |
| 129 | #define TCP_DEST_PORT 36 //2 |
| 130 | #define TCP_SEQ 38 //4 |
| 131 | #define TCP_ACK 42 //4 |
| 132 | #define TCP_HEADER_LENGTH 46 //1 0x50 |
| 133 | #define TCP_FLAGS 47 //1 SYNC=0x2;ACK=0x10;FIN=0x1 |
| 134 | #define TCP_WINDOW_SIZE 48 //2 |
| 135 | #define TCP_CHECKSUM 50 //2 |
| 136 | #define TCP_URGENT_POINTER 52 //2 |
| 137 | #define TCP_DATA 54 //length-N |
| 138 | |
| 139 | #define TCP_FLAGS_FIN 1 |
| 140 | #define TCP_FLAGS_SYN 2 |
| 141 | #define TCP_FLAGS_RST 4 |
| 142 | #define TCP_FLAGS_PSH 8 |
| 143 | #define TCP_FLAGS_ACK 16 |
| 144 | |
| 145 | //PING FIELD OFFSET LENGTH VALUE |
| 146 | #define PING_TYPE 34 //1 SEND=8;REPLY=0 |
| 147 | #define PING_CODE 35 //1 0 |
| 148 | #define PING_CHECKSUM 36 //2 |
| 149 | #define PING_ID 38 //2 |
| 150 | #define PING_SEQUENCE 40 //2 |
| 151 | #define PING_DATA 44 |
| 152 | |
| 153 | static void IPClose2(IPSocket *Socket); |
| 154 | |
| 155 | static uint8 ethernetAddressGateway[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; |
| 156 | #ifndef WIN32 |
| 157 | static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4}; |
| 158 | #else |
| 159 | static uint8 ethernetAddressPlasma[] = {0x00, 0x10, 0xdd, 0xce, 0x15, 0xd5}; |
| 160 | #endif |
| 161 | |
| 162 | static uint8 ipAddressPlasma[] = {0x9d, 0xfe, 0x28, 10}; //changed by DHCP |
| 163 | static uint8 ipAddressGateway[] = {0xff, 0xff, 0xff, 0xff}; //changed by DHCP |
| 164 | static uint32 ipAddressDns; //changed by DHCP |
| 165 | |
| 166 | static OS_Mutex_t *IPMutex; |
| 167 | static int FrameFreeCount; |
| 168 | static IPFrame *FrameFreeHead; |
| 169 | static IPFrame *FrameSendHead; |
| 170 | static IPFrame *FrameSendTail; |
| 171 | static IPFrame *FrameResendHead; |
| 172 | static IPFrame *FrameResendTail; |
| 173 | static IPSocket *SocketHead; |
| 174 | static uint32 Seconds; |
| 175 | static int DhcpRetrySeconds; |
| 176 | static IPFuncPtr FrameSendFunc; |
| 177 | static OS_MQueue_t *IPMQueue; |
| 178 | static OS_Thread_t *IPThread; |
| 179 | int IPVerbose=1; |
| 180 | |
| 181 | static const unsigned char dhcpDiscover[] = { |
| 182 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, //dest |
| 183 | 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //src |
| 184 | 0x08, 0x00, |
| 185 | 0x45, 0x00, 0x01, 0x48, 0x2e, 0xf5, 0x00, 0x00, //ip |
| 186 | 0x80, 0x11, 0x0a, 0xb1, 0x00, 0x00, 0x00, 0x00, |
| 187 | 0xff, 0xff, 0xff, 0xff, |
| 188 | 0x00, 0x44, 0x00, 0x43, 0x01, 0x34, 0x45, 0x66, //udp |
| 189 | 0x01, 0x01, 0x06, 0x00, 0x69, 0x26, 0xb5, 0x52 //dhcp |
| 190 | }; |
| 191 | |
| 192 | static unsigned char dhcpOptions[] = { |
| 193 | 0x63, 0x82, 0x53, 0x63, //cookie |
| 194 | 0x35, 0x01, 0x01, //DHCP Discover |
| 195 | 0x3d, 0x07, 0x01, 0x00, 0x10, 0xdd, 0xce, 0x15, 0xd4, //Client identifier |
| 196 | #ifndef WIN32 |
| 197 | 0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'a', //Host name |
| 198 | #else |
| 199 | 0x0c, 0x06, 'p', 'l', 'a', 's', 'm', 'b', //Host name |
| 200 | #endif |
| 201 | 0x37, 0x03, DHCP_PARAM_SUBNET, DHCP_PARAM_ROUTER, DHCP_PARAM_DNS, //Parameters |
| 202 | DHCP_END_OPTION |
| 203 | }; |
| 204 | |
| 205 | |
| 206 | //Get a free frame; can be called from an ISR |
| 207 | IPFrame *IPFrameGet(int freeCount) |
| 208 | { |
| 209 | IPFrame *frame=NULL; |
| 210 | uint32 state; |
| 211 | |
| 212 | state = OS_CriticalBegin(); |
| 213 | if(FrameFreeCount > freeCount) |
| 214 | { |
| 215 | frame = FrameFreeHead; |
| 216 | if(FrameFreeHead) |
| 217 | { |
| 218 | FrameFreeHead = FrameFreeHead->next; |
| 219 | --FrameFreeCount; |
| 220 | } |
| 221 | } |
| 222 | OS_CriticalEnd(state); |
| 223 | if(frame) |
| 224 | { |
| 225 | assert(frame->state == 0); |
| 226 | frame->state = 1; |
| 227 | } |
| 228 | return frame; |
| 229 | } |
| 230 | |
| 231 | |
| 232 | static void FrameFree(IPFrame *frame) |
| 233 | { |
| 234 | uint32 state; |
| 235 | |
| 236 | assert(frame->state == 1); |
| 237 | frame->state = 0; |
| 238 | state = OS_CriticalBegin(); |
| 239 | frame->next = FrameFreeHead; |
| 240 | FrameFreeHead = frame; |
| 241 | ++FrameFreeCount; |
| 242 | OS_CriticalEnd(state); |
| 243 | } |
| 244 | |
| 245 | |
| 246 | static void FrameInsert(IPFrame **head, IPFrame **tail, IPFrame *frame) |
| 247 | { |
| 248 | assert(frame->state == 1); |
| 249 | frame->state = 2; |
| 250 | OS_MutexPend(IPMutex); |
| 251 | frame->prev = NULL; |
| 252 | frame->next = *head; |
| 253 | if(*head) |
| 254 | (*head)->prev = frame; |
| 255 | *head = frame; |
| 256 | if(*tail == NULL) |
| 257 | *tail = frame; |
| 258 | OS_MutexPost(IPMutex); |
| 259 | } |
| 260 | |
| 261 | |
| 262 | static void FrameRemove(IPFrame **head, IPFrame **tail, IPFrame *frame) |
| 263 | { |
| 264 | assert(frame->state == 2); |
| 265 | frame->state = 1; |
| 266 | if(frame->prev) |
| 267 | frame->prev->next = frame->next; |
| 268 | else |
| 269 | *head = frame->next; |
| 270 | if(frame->next) |
| 271 | frame->next->prev = frame->prev; |
| 272 | else |
| 273 | *tail = frame->prev; |
| 274 | frame->prev = NULL; |
| 275 | frame->next = NULL; |
| 276 | } |
| 277 | |
| 278 | |
| 279 | static int IPChecksum(int checksum, const unsigned char *data, int length) |
| 280 | { |
| 281 | int i; |
| 282 | checksum = ~checksum & 0xffff; |
| 283 | for(i = 0; i < length-1; i += 2) |
| 284 | { |
| 285 | checksum += (data[i] << 8) | data[i+1]; |
| 286 | } |
| 287 | if(i < length) |
| 288 | checksum += data[i] << 8; |
| 289 | while(checksum >> 16) |
| 290 | checksum = (checksum & 0xffff) + (checksum >> 16); |
| 291 | checksum = ~checksum & 0xffff; |
| 292 | return checksum; |
| 293 | } |
| 294 | |
| 295 | |
| 296 | static int EthernetVerifyChecksums(const unsigned char *packet, int length) |
| 297 | { |
| 298 | int checksum, length2; |
| 299 | unsigned char pseudo[12]; |
| 300 | |
| 301 | //Calculate checksums |
| 302 | if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP |
| 303 | { |
| 304 | checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20); |
| 305 | if(checksum) |
| 306 | return -1; |
| 307 | if(packet[IP_PROTOCOL] == 0x01) //PING |
| 308 | { |
| 309 | checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE); |
| 310 | } |
| 311 | else if(packet[IP_PROTOCOL] == 0x11) //UDP |
| 312 | { |
| 313 | if(packet[UDP_CHECKSUM] == 0 && packet[UDP_CHECKSUM+1] == 0) |
| 314 | return 0; |
| 315 | memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); |
| 316 | memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); |
| 317 | pseudo[PSEUDO_ZERO] = 0; |
| 318 | pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; |
| 319 | memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2); |
| 320 | checksum = IPChecksum(0xffff, pseudo, 12); |
| 321 | length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1]; |
| 322 | checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length); |
| 323 | } |
| 324 | else if(packet[IP_PROTOCOL] == 0x06) //TCP |
| 325 | { |
| 326 | memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); |
| 327 | memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); |
| 328 | pseudo[PSEUDO_ZERO] = 0; |
| 329 | pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; |
| 330 | length = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1]; |
| 331 | length2 = length - 20; |
| 332 | pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8); |
| 333 | pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2; |
| 334 | checksum = IPChecksum(0xffff, pseudo, 12); |
| 335 | checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2); |
| 336 | } |
| 337 | if(checksum) |
| 338 | return -1; |
| 339 | } |
| 340 | return 0; |
| 341 | } |
| 342 | |
| 343 | |
| 344 | static void IPFrameReschedule(IPFrame *frame) |
| 345 | { |
| 346 | int length; |
| 347 | length = frame->length - TCP_DATA; |
| 348 | if(frame->packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN)) |
| 349 | ++length; |
| 350 | if(frame->socket == NULL || frame->socket->state == IP_UDP || length == 0 || |
| 351 | frame->socket->state == IP_PING || ++frame->retryCnt > 4) |
| 352 | { |
| 353 | FrameFree(frame); //can't be ACK'ed |
| 354 | } |
| 355 | #ifdef WIN32 |
| 356 | else if(FrameFreeCount < FRAME_COUNT_SYNC) |
| 357 | { |
| 358 | FrameFree(frame); //can't be ACK'ed |
| 359 | } |
| 360 | #endif |
| 361 | else |
| 362 | { |
| 363 | //Put on resend list until TCP ACK'ed |
| 364 | frame->timeout = (short)(RETRANSMIT_TIME * frame->retryCnt); |
| 365 | FrameInsert(&FrameResendHead, &FrameResendTail, frame); |
| 366 | } |
| 367 | } |
| 368 | |
| 369 | |
| 370 | static void IPSendFrame(IPFrame *frame) |
| 371 | { |
| 372 | uint32 message[4]; |
| 373 | |
| 374 | if(FrameSendFunc) |
| 375 | { |
| 376 | //Single threaded |
| 377 | FrameSendFunc(frame->packet, frame->length); |
| 378 | IPFrameReschedule(frame); |
| 379 | } |
| 380 | else |
| 381 | { |
| 382 | //Add Packet to send queue |
| 383 | FrameInsert(&FrameSendHead, &FrameSendTail, frame); |
| 384 | |
| 385 | //Wakeup sender thread |
| 386 | message[0] = 2; |
| 387 | OS_MQueueSend(IPMQueue, message); |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | |
| 392 | static void IPSendPacket(IPSocket *socket, IPFrame *frame, int length) |
| 393 | { |
| 394 | int checksum, length2=length; |
| 395 | unsigned char pseudo[12], *packet=frame->packet; |
| 396 | |
| 397 | frame->length = (uint16)length; |
| 398 | |
| 399 | //Calculate checksums |
| 400 | if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP |
| 401 | { |
| 402 | length2 = length - IP_VERSION_LENGTH; |
| 403 | packet[IP_LENGTH] = (uint8)(length2 >> 8); |
| 404 | packet[IP_LENGTH+1] = (uint8)length2; |
| 405 | memset(packet+IP_CHECKSUM, 0, 2); |
| 406 | checksum = IPChecksum(0xffff, packet+IP_VERSION_LENGTH, 20); |
| 407 | packet[IP_CHECKSUM] = (unsigned char)(checksum >> 8); |
| 408 | packet[IP_CHECKSUM+1] = (unsigned char)checksum; |
| 409 | if(packet[IP_PROTOCOL] == 0x01) //ICMP & PING |
| 410 | { |
| 411 | memset(packet+PING_CHECKSUM, 0, 2); |
| 412 | checksum = IPChecksum(0xffff, packet+PING_TYPE, length-PING_TYPE); |
| 413 | packet[PING_CHECKSUM] = (unsigned char)(checksum >> 8); |
| 414 | packet[PING_CHECKSUM+1] = (unsigned char)checksum; |
| 415 | } |
| 416 | else if(packet[IP_PROTOCOL] == 0x11) //UDP |
| 417 | { |
| 418 | length2 = length - UDP_SOURCE_PORT; |
| 419 | packet[UDP_LENGTH] = (uint8)(length2 >> 8); |
| 420 | packet[UDP_LENGTH+1] = (uint8)length2; |
| 421 | memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); |
| 422 | memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); |
| 423 | pseudo[PSEUDO_ZERO] = 0; |
| 424 | pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; |
| 425 | memcpy(pseudo+PSEUDO_LENGTH, packet+UDP_LENGTH, 2); |
| 426 | checksum = IPChecksum(0xffff, pseudo, 12); |
| 427 | memset(packet+UDP_CHECKSUM, 0, 2); |
| 428 | length2 = (packet[UDP_LENGTH] << 8) + packet[UDP_LENGTH+1]; |
| 429 | checksum = IPChecksum(checksum, packet+UDP_SOURCE_PORT, length2); |
| 430 | packet[UDP_CHECKSUM] = (unsigned char)(checksum >> 8); |
| 431 | packet[UDP_CHECKSUM+1] = (unsigned char)checksum; |
| 432 | } |
| 433 | else if(packet[IP_PROTOCOL] == 0x06) //TCP |
| 434 | { |
| 435 | memcpy(pseudo+PSEUDO_IP_SOURCE, packet+IP_SOURCE, 4); |
| 436 | memcpy(pseudo+PSEUDO_IP_DEST, packet+IP_DEST, 4); |
| 437 | pseudo[PSEUDO_ZERO] = 0; |
| 438 | pseudo[PSEUDO_IP_PROTOCOL] = packet[IP_PROTOCOL]; |
| 439 | length2 = (packet[IP_LENGTH] << 8) + packet[IP_LENGTH+1]; |
| 440 | length2 = length2 - 20; |
| 441 | pseudo[PSEUDO_LENGTH] = (unsigned char)(length2 >> 8); |
| 442 | pseudo[PSEUDO_LENGTH+1] = (unsigned char)length2; |
| 443 | checksum = IPChecksum(0xffff, pseudo, 12); |
| 444 | memset(packet+TCP_CHECKSUM, 0, 2); |
| 445 | checksum = IPChecksum(checksum, packet+TCP_SOURCE_PORT, length2); |
| 446 | packet[TCP_CHECKSUM] = (unsigned char)(checksum >> 8); |
| 447 | packet[TCP_CHECKSUM+1] = (unsigned char)checksum; |
| 448 | } |
| 449 | } |
| 450 | |
| 451 | length2 = length - TCP_DATA; |
| 452 | if(socket && (packet[TCP_FLAGS] & (TCP_FLAGS_FIN | TCP_FLAGS_SYN))) |
| 453 | length2 = 1; |
| 454 | frame->socket = socket; |
| 455 | frame->timeout = 0; |
| 456 | frame->retryCnt = 0; |
| 457 | if(socket) |
| 458 | frame->seqEnd = socket->seq + length2; |
| 459 | IPSendFrame(frame); |
| 460 | } |
| 461 | |
| 462 | |
| 463 | static void TCPSendPacket(IPSocket *socket, IPFrame *frame, int length) |
| 464 | { |
| 465 | uint8 *packet = frame->packet; |
| 466 | int flags, count; |
| 467 | |
| 468 | flags = packet[TCP_FLAGS]; |
| 469 | memcpy(packet, socket->headerSend, TCP_SEQ); |
| 470 | packet[TCP_FLAGS] = (uint8)flags; |
| 471 | if(flags & TCP_FLAGS_SYN) |
| 472 | packet[TCP_HEADER_LENGTH] = 0x60; //set maximum segment size |
| 473 | else |
| 474 | packet[TCP_HEADER_LENGTH] = 0x50; |
| 475 | packet[TCP_SEQ] = (uint8)(socket->seq >> 24); |
| 476 | packet[TCP_SEQ+1] = (uint8)(socket->seq >> 16); |
| 477 | packet[TCP_SEQ+2] = (uint8)(socket->seq >> 8); |
| 478 | packet[TCP_SEQ+3] = (uint8)socket->seq; |
| 479 | packet[TCP_ACK] = (uint8)(socket->ack >> 24); |
| 480 | packet[TCP_ACK+1] = (uint8)(socket->ack >> 16); |
| 481 | packet[TCP_ACK+2] = (uint8)(socket->ack >> 8); |
| 482 | packet[TCP_ACK+3] = (uint8)socket->ack; |
| 483 | count = RECEIVE_WINDOW - (socket->ack - socket->ackProcessed); |
| 484 | if(count < 0) |
| 485 | count = 0; |
| 486 | packet[TCP_WINDOW_SIZE] = (uint8)(count >> 8); |
| 487 | packet[TCP_WINDOW_SIZE+1] = (uint8)count; |
| 488 | packet[TCP_URGENT_POINTER] = 0; |
| 489 | packet[TCP_URGENT_POINTER+1] = 0; |
| 490 | IPSendPacket(socket, frame, length); |
| 491 | } |
| 492 | |
| 493 | |
| 494 | static void EthernetCreateResponse(unsigned char *packetOut, |
| 495 | const unsigned char *packet, |
| 496 | int length) |
| 497 | { |
| 498 | //Swap destination and source fields |
| 499 | memcpy(packetOut, packet, length); |
| 500 | memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6); |
| 501 | memcpy(packetOut+ETHERNET_SOURCE, packet+ETHERNET_DEST, 6); |
| 502 | if(packet[ETHERNET_FRAME_TYPE+1] == 0x00) //IP |
| 503 | { |
| 504 | memcpy(packetOut+IP_SOURCE, packet+IP_DEST, 4); |
| 505 | memcpy(packetOut+IP_DEST, packet+IP_SOURCE, 4); |
| 506 | if(packet[IP_PROTOCOL] == 0x06 || packet[IP_PROTOCOL] == 0x11) //TCP/UDP |
| 507 | { |
| 508 | memcpy(packetOut+TCP_SOURCE_PORT, packet+TCP_DEST_PORT, 2); |
| 509 | memcpy(packetOut+TCP_DEST_PORT, packet+TCP_SOURCE_PORT, 2); |
| 510 | } |
| 511 | } |
| 512 | } |
| 513 | |
| 514 | |
| 515 | static void IPDhcp(const unsigned char *packet, int length, int state) |
| 516 | { |
| 517 | uint8 *packetOut, *ptr; |
| 518 | const uint8 *ptr2; |
| 519 | IPFrame *frame; |
| 520 | static int request=0; |
| 521 | |
| 522 | if(state == 1) |
| 523 | { |
| 524 | //Create DHCP Discover |
| 525 | frame = IPFrameGet(0); |
| 526 | if(frame == NULL) |
| 527 | return; |
| 528 | packetOut = frame->packet; |
| 529 | memset(packetOut, 0, 512); |
| 530 | memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover)); |
| 531 | memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); |
| 532 | memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6); |
| 533 | memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions)); |
| 534 | memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6); |
| 535 | IPSendPacket(NULL, frame, 400); |
| 536 | request = DHCP_DISCOVER; |
| 537 | DhcpRetrySeconds = 2; |
| 538 | } |
| 539 | else if(state == 2 && memcmp(packet+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6) == 0) |
| 540 | { |
| 541 | if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_OFFER && request == DHCP_DISCOVER) |
| 542 | { |
| 543 | //Process DHCP Offer and send DHCP Request |
| 544 | frame = IPFrameGet(0); |
| 545 | if(frame == NULL) |
| 546 | return; |
| 547 | packetOut = frame->packet; |
| 548 | memset(packetOut, 0, 512); |
| 549 | memcpy(packetOut, dhcpDiscover, sizeof(dhcpDiscover)); |
| 550 | memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); |
| 551 | memcpy(packetOut+DHCP_CLIENT_ETHERNET, ethernetAddressPlasma, 6); |
| 552 | memcpy(packetOut+DHCP_MAGIC_COOKIE, dhcpOptions, sizeof(dhcpOptions)); |
| 553 | memcpy(packetOut+DHCP_MAGIC_COOKIE+10, ethernetAddressPlasma, 6); |
| 554 | request = DHCP_REQUEST; |
| 555 | packetOut[DHCP_MAGIC_COOKIE+6] = DHCP_REQUEST; |
| 556 | ptr = packetOut+DHCP_MAGIC_COOKIE+sizeof(dhcpOptions)-1; |
| 557 | ptr[0] = DHCP_REQUEST_IP; |
| 558 | ptr[1] = 4; |
| 559 | memcpy(ptr+2, packet+DHCP_YOUR_IP, 4); |
| 560 | ptr[6] = DHCP_REQUEST_SERV_IP; |
| 561 | ptr[7] = 4; |
| 562 | memcpy(ptr+8, packet+DHCP_SERVER_IP, 4); |
| 563 | ptr[12] = DHCP_END_OPTION; |
| 564 | IPSendPacket(NULL, frame, 400); |
| 565 | } |
| 566 | else if(packet[DHCP_MAGIC_COOKIE+6] == DHCP_ACK && request == DHCP_REQUEST) |
| 567 | { |
| 568 | //Process DHCP Ack |
| 569 | request = 0; |
| 570 | DhcpRetrySeconds = 3600*4; |
| 571 | memcpy(ipAddressPlasma, packet+DHCP_YOUR_IP, 4); |
| 572 | printf("IP=%d.%d.%d.%d ", ipAddressPlasma[0], ipAddressPlasma[1], |
| 573 | ipAddressPlasma[2], ipAddressPlasma[3]); |
| 574 | memcpy(ipAddressGateway, packet+DHCP_GATEWAY_IP, 4); |
| 575 | if(ipAddressGateway[0] == 0 && ipAddressGateway[1] == 0 && |
| 576 | ipAddressGateway[2] == 0 && ipAddressGateway[3] == 0) |
| 577 | memcpy(ipAddressGateway, packet+DHCP_SERVER_IP, 4); |
| 578 | printf("GW=%d.%d.%d.%d ", ipAddressGateway[0], ipAddressGateway[1], |
| 579 | ipAddressGateway[2], ipAddressGateway[3]); |
| 580 | memcpy(ethernetAddressGateway, packet+ETHERNET_SOURCE, 6); |
| 581 | ptr2 = packet+DHCP_MAGIC_COOKIE+4; |
| 582 | while(ptr2[0] != DHCP_END_OPTION && (int)(ptr2 - packet) < length) |
| 583 | { |
| 584 | if(ptr2[0] == DHCP_PARAM_DNS) |
| 585 | { |
| 586 | ipAddressDns = (ptr2[2] << 24) | (ptr2[3] << 16) | (ptr2[4] << 8) | ptr2[5]; |
| 587 | printf("DNS=%d.%d.%d.%d ", ptr2[2], ptr2[3], ptr2[4], ptr2[5]); |
| 588 | } |
| 589 | ptr2 += ptr2[1] + 2; |
| 590 | } |
| 591 | |
| 592 | //Check if DHCP reply came from gateway |
| 593 | if(memcmp(packet+IP_SOURCE, ipAddressGateway, 4)) |
| 594 | { |
| 595 | //Send ARP to gateway |
| 596 | frame = IPFrameGet(0); |
| 597 | if(frame == NULL) |
| 598 | return; |
| 599 | packetOut = frame->packet; |
| 600 | memset(packetOut, 0, 512); |
| 601 | memset(packetOut+ETHERNET_DEST, 0xff, 6); |
| 602 | memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); |
| 603 | packetOut[ETHERNET_FRAME_TYPE] = 0x08; |
| 604 | packetOut[ETHERNET_FRAME_TYPE+1] = 0x06; |
| 605 | packetOut[ARP_HARD_TYPE+1] = 0x01; |
| 606 | packetOut[ARP_PROT_TYPE] = 0x08; |
| 607 | packetOut[ARP_HARD_SIZE] = 0x06; |
| 608 | packetOut[ARP_PROT_SIZE] = 0x04; |
| 609 | packetOut[ARP_OP+1] = 1; |
| 610 | memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6); |
| 611 | memcpy(packetOut+ARP_IP_SENDER, ipAddressPlasma, 4); |
| 612 | memcpy(packetOut+ARP_IP_TARGET, ipAddressGateway, 4); |
| 613 | IPSendPacket(NULL, frame, 60); |
| 614 | } |
| 615 | } |
| 616 | } |
| 617 | } |
| 618 | |
| 619 | |
| 620 | uint32 IPAddressSelf(void) |
| 621 | { |
| 622 | return (ipAddressPlasma[0] << 24) | (ipAddressPlasma[1] << 16) | |
| 623 | (ipAddressPlasma[2] << 8) | ipAddressPlasma[3]; |
| 624 | } |
| 625 | |
| 626 | |
| 627 | static int IPProcessTCPPacket(IPFrame *frameIn) |
| 628 | { |
| 629 | uint32 seq, ack; |
| 630 | int length, ip_length, bytes, rc=0, notify=0; |
| 631 | IPSocket *socket, *socketNew; |
| 632 | IPFrame *frameOut, *frame2, *framePrev; |
| 633 | uint8 *packet, *packetOut; |
| 634 | |
| 635 | packet = frameIn->packet; |
| 636 | length = frameIn->length; |
| 637 | |
| 638 | ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1]; |
| 639 | seq = (packet[TCP_SEQ] << 24) | (packet[TCP_SEQ+1] << 16) | |
| 640 | (packet[TCP_SEQ+2] << 8) | packet[TCP_SEQ+3]; |
| 641 | ack = (packet[TCP_ACK] << 24) | (packet[TCP_ACK+1] << 16) | |
| 642 | (packet[TCP_ACK+2] << 8) | packet[TCP_ACK+3]; |
| 643 | |
| 644 | //Check if start of connection |
| 645 | if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == TCP_FLAGS_SYN) |
| 646 | { |
| 647 | if(IPVerbose) |
| 648 | printf("S"); |
| 649 | //Check if duplicate SYN |
| 650 | for(socket = SocketHead; socket; socket = socket->next) |
| 651 | { |
| 652 | if(socket->state != IP_LISTEN && |
| 653 | packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && |
| 654 | memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 && |
| 655 | memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0) |
| 656 | { |
| 657 | if(IPVerbose) |
| 658 | printf("s"); |
| 659 | return 0; |
| 660 | } |
| 661 | } |
| 662 | |
| 663 | //Find an open port |
| 664 | for(socket = SocketHead; socket; socket = socket->next) |
| 665 | { |
| 666 | if(socket->state == IP_LISTEN && |
| 667 | packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && |
| 668 | memcmp(packet+TCP_DEST_PORT, socket->headerRcv+TCP_DEST_PORT, 2) == 0) |
| 669 | { |
| 670 | //Create a new socket |
| 671 | frameOut = IPFrameGet(FRAME_COUNT_SYNC); |
| 672 | if(frameOut == NULL) |
| 673 | return 0; |
| 674 | socketNew = (IPSocket*)malloc(sizeof(IPSocket)); |
| 675 | if(socketNew == NULL) |
| 676 | return 0; |
| 677 | memcpy(socketNew, socket, sizeof(IPSocket)); |
| 678 | socketNew->state = IP_TCP; |
| 679 | socketNew->timeout = SOCKET_TIMEOUT; |
| 680 | socketNew->ack = seq; |
| 681 | socketNew->ackProcessed = seq + 1; |
| 682 | socketNew->seq = socketNew->ack + 0x12345678; |
| 683 | socketNew->seqReceived = socketNew->seq; |
| 684 | socketNew->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1]; |
| 685 | |
| 686 | //Send ACK |
| 687 | packetOut = frameOut->packet; |
| 688 | EthernetCreateResponse(packetOut, packet, length); |
| 689 | memcpy(socketNew->headerRcv, packet, TCP_SEQ); |
| 690 | memcpy(socketNew->headerSend, packetOut, TCP_SEQ); |
| 691 | packetOut[TCP_FLAGS] = TCP_FLAGS_SYN | TCP_FLAGS_ACK; |
| 692 | ++socketNew->ack; |
| 693 | packetOut[TCP_DATA] = 2; //maximum segment size = 536 |
| 694 | packetOut[TCP_DATA+1] = 4; |
| 695 | packetOut[TCP_DATA+2] = 2; |
| 696 | packetOut[TCP_DATA+3] = 24; |
| 697 | TCPSendPacket(socketNew, frameOut, TCP_DATA+4); |
| 698 | ++socketNew->seq; |
| 699 | |
| 700 | //Add socket to linked list |
| 701 | OS_MutexPend(IPMutex); |
| 702 | socketNew->next = SocketHead; |
| 703 | socketNew->prev = NULL; |
| 704 | if(SocketHead) |
| 705 | SocketHead->prev = socketNew; |
| 706 | SocketHead = socketNew; |
| 707 | OS_MutexPost(IPMutex); |
| 708 | if(socketNew->funcPtr) |
| 709 | OS_Job(socketNew->funcPtr, socketNew, 0, 0); |
| 710 | return 0; |
| 711 | } |
| 712 | } |
| 713 | |
| 714 | //Send reset |
| 715 | frameOut = IPFrameGet(0); |
| 716 | if(frameOut == NULL) |
| 717 | return 0; |
| 718 | packetOut = frameOut->packet; |
| 719 | EthernetCreateResponse(packetOut, packet, TCP_DATA); |
| 720 | memset(packetOut+TCP_SEQ, 0, 4); |
| 721 | ++seq; |
| 722 | packetOut[TCP_ACK] = (uint8)(seq >> 24); |
| 723 | packetOut[TCP_ACK+1] = (uint8)(seq >> 16); |
| 724 | packetOut[TCP_ACK+2] = (uint8)(seq >> 8); |
| 725 | packetOut[TCP_ACK+3] = (uint8)seq; |
| 726 | packetOut[TCP_HEADER_LENGTH] = 0x50; |
| 727 | packetOut[TCP_FLAGS] = TCP_FLAGS_RST; |
| 728 | IPSendPacket(NULL, frameOut, TCP_DATA); |
| 729 | return 0; |
| 730 | } |
| 731 | |
| 732 | //Find an open socket |
| 733 | for(socket = SocketHead; socket; socket = socket->next) |
| 734 | { |
| 735 | if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && |
| 736 | memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 && |
| 737 | memcmp(packet+TCP_SOURCE_PORT, socket->headerRcv+TCP_SOURCE_PORT, 4) == 0) |
| 738 | { |
| 739 | break; |
| 740 | } |
| 741 | } |
| 742 | if(socket == NULL) |
| 743 | { |
| 744 | return 0; |
| 745 | } |
| 746 | |
| 747 | //Determine window |
| 748 | socket->seqWindow = (packet[TCP_WINDOW_SIZE] << 8) | packet[TCP_WINDOW_SIZE+1]; |
| 749 | bytes = ip_length - (TCP_DATA - IP_VERSION_LENGTH); |
| 750 | |
| 751 | //Check if packets can be removed from retransmition list |
| 752 | if(packet[TCP_FLAGS] & TCP_FLAGS_ACK) |
| 753 | { |
| 754 | if(ack != socket->seqReceived) |
| 755 | { |
| 756 | OS_MutexPend(IPMutex); |
| 757 | for(frame2 = FrameResendHead; frame2; ) |
| 758 | { |
| 759 | framePrev = frame2; |
| 760 | frame2 = frame2->next; |
| 761 | if(framePrev->socket == socket && (int)(ack - framePrev->seqEnd) >= 0) |
| 762 | { |
| 763 | //Remove packet from retransmition queue |
| 764 | if(socket->timeout) |
| 765 | socket->timeout = socket->timeoutReset; |
| 766 | FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); |
| 767 | FrameFree(framePrev); |
| 768 | } |
| 769 | } |
| 770 | OS_MutexPost(IPMutex); |
| 771 | socket->seqReceived = ack; |
| 772 | socket->resentDone = 0; |
| 773 | } |
| 774 | else if(ack == socket->seqReceived && bytes == 0 && |
| 775 | (packet[TCP_FLAGS] & (TCP_FLAGS_RST | TCP_FLAGS_FIN)) == 0 && |
| 776 | socket->resentDone == 0) |
| 777 | { |
| 778 | //Detected that packet was lost, resend all |
| 779 | if(IPVerbose) |
| 780 | printf("A"); |
| 781 | OS_MutexPend(IPMutex); |
| 782 | for(frame2 = FrameResendHead; frame2; ) |
| 783 | { |
| 784 | framePrev = frame2; |
| 785 | frame2 = frame2->next; |
| 786 | if(framePrev->socket == socket) |
| 787 | { |
| 788 | //Remove packet from retransmition queue |
| 789 | FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); |
| 790 | IPSendFrame(framePrev); |
| 791 | } |
| 792 | } |
| 793 | OS_MutexPost(IPMutex); |
| 794 | socket->resentDone = 1; |
| 795 | } |
| 796 | } |
| 797 | |
| 798 | //Check if SYN/ACK |
| 799 | if((packet[TCP_FLAGS] & (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) == |
| 800 | (TCP_FLAGS_SYN | TCP_FLAGS_ACK)) |
| 801 | { |
| 802 | //Ack SYN/ACK |
| 803 | socket->ack = seq + 1; |
| 804 | socket->ackProcessed = seq + 1; |
| 805 | frameOut = IPFrameGet(FRAME_COUNT_SEND); |
| 806 | if(frameOut) |
| 807 | { |
| 808 | frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK; |
| 809 | TCPSendPacket(socket, frameOut, TCP_DATA); |
| 810 | } |
| 811 | if(socket->funcPtr) |
| 812 | OS_Job(socket->funcPtr, socket, 0, 0); |
| 813 | return 0; |
| 814 | } |
| 815 | if(packet[TCP_HEADER_LENGTH] != 0x50) |
| 816 | { |
| 817 | if(IPVerbose) |
| 818 | printf("length error\n"); |
| 819 | return 0; |
| 820 | } |
| 821 | |
| 822 | //Check if RST flag set |
| 823 | if(packet[TCP_FLAGS] & TCP_FLAGS_RST) |
| 824 | { |
| 825 | notify = 1; |
| 826 | if(socket->state == IP_FIN_SERVER) |
| 827 | IPClose2(socket); |
| 828 | else if(socket->state == IP_TCP) |
| 829 | socket->state = IP_FIN_CLIENT; |
| 830 | } |
| 831 | //Copy packet into socket |
| 832 | else if(socket->ack == seq && bytes > 0) |
| 833 | { |
| 834 | //Insert packet into socket linked list |
| 835 | notify = 1; |
| 836 | if(socket->timeout) |
| 837 | socket->timeout = socket->timeoutReset; |
| 838 | if(IPVerbose) |
| 839 | printf("D"); |
| 840 | if(frameIn->length > ip_length + IP_VERSION_LENGTH) |
| 841 | frameIn->length = (uint16)(ip_length + IP_VERSION_LENGTH); |
| 842 | FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn); |
| 843 | socket->ack += bytes; |
| 844 | |
| 845 | //Ack data |
| 846 | frameOut = IPFrameGet(FRAME_COUNT_SEND); |
| 847 | if(frameOut) |
| 848 | { |
| 849 | frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK; |
| 850 | TCPSendPacket(socket, frameOut, TCP_DATA); |
| 851 | } |
| 852 | |
| 853 | //Using frame |
| 854 | rc = 1; |
| 855 | } |
| 856 | else if(bytes) |
| 857 | { |
| 858 | //Ack with current offset since data missing |
| 859 | frameOut = IPFrameGet(FRAME_COUNT_SEND); |
| 860 | if(frameOut) |
| 861 | { |
| 862 | frameOut->packet[TCP_FLAGS] = TCP_FLAGS_ACK; |
| 863 | TCPSendPacket(socket, frameOut, TCP_DATA); |
| 864 | } |
| 865 | } |
| 866 | |
| 867 | //Check if FIN flag set |
| 868 | if(packet[TCP_FLAGS] & TCP_FLAGS_FIN && socket->ack >= seq) |
| 869 | { |
| 870 | notify = 1; |
| 871 | socket->timeout = SOCKET_TIMEOUT; |
| 872 | if(IPVerbose) |
| 873 | printf("F"); |
| 874 | frameOut = IPFrameGet(0); |
| 875 | if(frameOut == NULL) |
| 876 | return 0; |
| 877 | packetOut = frameOut->packet; |
| 878 | packetOut[TCP_FLAGS] = TCP_FLAGS_ACK; |
| 879 | ++socket->ack; |
| 880 | TCPSendPacket(socket, frameOut, TCP_DATA); |
| 881 | if(socket->state == IP_FIN_SERVER) |
| 882 | IPClose2(socket); |
| 883 | else if(socket->state == IP_TCP) |
| 884 | socket->state = IP_FIN_CLIENT; |
| 885 | } |
| 886 | |
| 887 | //Notify application |
| 888 | if(socket->funcPtr && notify) |
| 889 | OS_Job(socket->funcPtr, socket, 0, 0); |
| 890 | return rc; |
| 891 | } |
| 892 | |
| 893 | |
| 894 | int IPProcessEthernetPacket(IPFrame *frameIn, int length) |
| 895 | { |
| 896 | int ip_length, rc; |
| 897 | IPSocket *socket; |
| 898 | IPFrame *frameOut; |
| 899 | uint8 *packet, *packetOut; |
| 900 | |
| 901 | packet = frameIn->packet; |
| 902 | frameIn->length = (uint16)length; |
| 903 | |
| 904 | if(packet[ETHERNET_FRAME_TYPE] != 0x08 || frameIn->length > PACKET_SIZE) |
| 905 | return 0; //wrong ethernet type, packet not used |
| 906 | |
| 907 | //ARP? |
| 908 | if(packet[ETHERNET_FRAME_TYPE+1] == 0x06) |
| 909 | { |
| 910 | //Check if ARP reply |
| 911 | if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) == 0 && |
| 912 | packet[ARP_OP+1] == 2 && memcmp(packet+ARP_IP_SENDER, ipAddressGateway, 4) == 0) |
| 913 | { |
| 914 | //Found MAC address for gateway |
| 915 | memcpy(ethernetAddressGateway, packet+ARP_ETHERNET_SENDER, 6); |
| 916 | return 0; |
| 917 | } |
| 918 | |
| 919 | //Check if ARP request |
| 920 | if(packet[ARP_OP] != 0 || packet[ARP_OP+1] != 1 || |
| 921 | memcmp(packet+ARP_IP_TARGET, ipAddressPlasma, 4)) |
| 922 | return 0; |
| 923 | //Create ARP response |
| 924 | frameOut = IPFrameGet(0); |
| 925 | if(frameOut == NULL) |
| 926 | return 0; |
| 927 | packetOut = frameOut->packet; |
| 928 | memcpy(packetOut, packet, frameIn->length); |
| 929 | memcpy(packetOut+ETHERNET_DEST, packet+ETHERNET_SOURCE, 6); |
| 930 | memcpy(packetOut+ETHERNET_SOURCE, ethernetAddressPlasma, 6); |
| 931 | packetOut[ARP_OP+1] = 2; //ARP reply |
| 932 | memcpy(packetOut+ARP_ETHERNET_SENDER, ethernetAddressPlasma, 6); |
| 933 | memcpy(packetOut+ARP_IP_SENDER, packet+ARP_IP_TARGET, 4); |
| 934 | memcpy(packetOut+ARP_ETHERNET_TARGET, packet+ARP_ETHERNET_SENDER, 6); |
| 935 | memcpy(packetOut+ARP_IP_TARGET, packet+ARP_IP_SENDER, 4); |
| 936 | IPSendPacket(NULL, frameOut, frameIn->length); |
| 937 | return 0; |
| 938 | } |
| 939 | |
| 940 | //Check if proper type of packet |
| 941 | ip_length = (packet[IP_LENGTH] << 8) | packet[IP_LENGTH+1]; |
| 942 | if(frameIn->length < UDP_DATA || ip_length > frameIn->length - IP_VERSION_LENGTH) |
| 943 | return 0; |
| 944 | if(packet[ETHERNET_FRAME_TYPE+1] != 0x00 || |
| 945 | packet[IP_VERSION_LENGTH] != 0x45) |
| 946 | return 0; |
| 947 | |
| 948 | //Check if DHCP reply |
| 949 | if(packet[IP_PROTOCOL] == 0x11 && |
| 950 | packet[UDP_SOURCE_PORT] == 0 && packet[UDP_SOURCE_PORT+1] == 67 && |
| 951 | packet[UDP_DEST_PORT] == 0 && packet[UDP_DEST_PORT+1] == 68) |
| 952 | { |
| 953 | IPDhcp(packet, frameIn->length, 2); //DHCP reply |
| 954 | return 0; |
| 955 | } |
| 956 | |
| 957 | //Check if correct destination address |
| 958 | if(memcmp(packet+ETHERNET_DEST, ethernetAddressPlasma, 6) || |
| 959 | memcmp(packet+IP_DEST, ipAddressPlasma, 4)) |
| 960 | return 0; |
| 961 | rc = EthernetVerifyChecksums(packet, frameIn->length); |
| 962 | #ifndef WIN32 |
| 963 | if(rc && FrameSendFunc) |
| 964 | { |
| 965 | printf("C "); |
| 966 | return 0; |
| 967 | } |
| 968 | #endif |
| 969 | |
| 970 | //PING request? |
| 971 | if(packet[IP_PROTOCOL] == 1) |
| 972 | { |
| 973 | if(packet[PING_TYPE] == 0) //PING reply |
| 974 | { |
| 975 | for(socket = SocketHead; socket; socket = socket->next) |
| 976 | { |
| 977 | if(socket->state == IP_PING && |
| 978 | memcmp(packet+IP_SOURCE, socket->headerSend+IP_DEST, 4) == 0) |
| 979 | { |
| 980 | OS_Job(socket->funcPtr, socket, 0, 0); |
| 981 | return 0; |
| 982 | } |
| 983 | } |
| 984 | } |
| 985 | if(packet[PING_TYPE] != 8) |
| 986 | return 0; |
| 987 | frameOut = IPFrameGet(FRAME_COUNT_SEND); |
| 988 | if(frameOut == NULL) |
| 989 | return 0; |
| 990 | packetOut = frameOut->packet; |
| 991 | EthernetCreateResponse(packetOut, packet, frameIn->length); |
| 992 | frameOut->packet[PING_TYPE] = 0; //PING reply |
| 993 | IPSendPacket(NULL, frameOut, frameIn->length); |
| 994 | return 0; |
| 995 | } |
| 996 | |
| 997 | //TCP packet? |
| 998 | if(packet[IP_PROTOCOL] == 0x06) |
| 999 | { |
| 1000 | return IPProcessTCPPacket(frameIn); |
| 1001 | } |
| 1002 | |
| 1003 | //UDP packet? |
| 1004 | if(packet[IP_PROTOCOL] == 0x11) |
| 1005 | { |
| 1006 | //Find open socket |
| 1007 | for(socket = SocketHead; socket; socket = socket->next) |
| 1008 | { |
| 1009 | if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && |
| 1010 | memcmp(packet+IP_SOURCE, socket->headerRcv+IP_SOURCE, 8) == 0 && |
| 1011 | memcmp(packet+UDP_SOURCE_PORT, socket->headerRcv+UDP_SOURCE_PORT, 2) == 0) |
| 1012 | { |
| 1013 | break; |
| 1014 | } |
| 1015 | } |
| 1016 | |
| 1017 | if(socket == NULL) |
| 1018 | { |
| 1019 | //Find listening socket |
| 1020 | for(socket = SocketHead; socket; socket = socket->next) |
| 1021 | { |
| 1022 | if(packet[IP_PROTOCOL] == socket->headerRcv[IP_PROTOCOL] && |
| 1023 | memcmp(packet+UDP_DEST_PORT, socket->headerRcv+UDP_DEST_PORT, 2) == 0) |
| 1024 | { |
| 1025 | EthernetCreateResponse(socket->headerSend, packet, UDP_DATA); |
| 1026 | break; |
| 1027 | } |
| 1028 | } |
| 1029 | } |
| 1030 | |
| 1031 | if(socket) |
| 1032 | { |
| 1033 | if(IPVerbose) |
| 1034 | printf("U"); |
| 1035 | FrameInsert(&socket->frameReadHead, &socket->frameReadTail, frameIn); |
| 1036 | OS_Job(socket->funcPtr, socket, 0, 0); |
| 1037 | return 1; |
| 1038 | } |
| 1039 | } |
| 1040 | return 0; |
| 1041 | } |
| 1042 | |
| 1043 | |
| 1044 | #ifndef WIN32 |
| 1045 | static void IPMainThread(void *arg) |
| 1046 | { |
| 1047 | uint32 message[4]; |
| 1048 | int rc; |
| 1049 | IPFrame *frame, *frameOut=NULL; |
| 1050 | uint32 ticks, ticksLast; |
| 1051 | (void)arg; |
| 1052 | |
| 1053 | ticksLast = OS_ThreadTime(); |
| 1054 | memset(message, 0, sizeof(message)); |
| 1055 | |
| 1056 | for(;;) |
| 1057 | { |
| 1058 | Led(7, 0); |
| 1059 | rc = OS_MQueueGet(IPMQueue, message, 10); |
| 1060 | if(rc == 0) |
| 1061 | { |
| 1062 | frame = (IPFrame*)message[1]; |
| 1063 | if(message[0] == 0) //frame received |
| 1064 | { |
| 1065 | Led(7, 1); |
| 1066 | frame->length = (uint16)message[2]; |
| 1067 | rc = IPProcessEthernetPacket(frame, frame->length); |
| 1068 | if(rc == 0) |
| 1069 | FrameFree(frame); |
| 1070 | } |
| 1071 | else if(message[0] == 1) //frame sent |
| 1072 | { |
| 1073 | Led(7, 2); |
| 1074 | assert(frame == frameOut); |
| 1075 | IPFrameReschedule(frame); |
| 1076 | frameOut = NULL; |
| 1077 | } |
| 1078 | else if(message[0] == 2) //frame ready to send |
| 1079 | { |
| 1080 | } |
| 1081 | } |
| 1082 | |
| 1083 | if(frameOut == NULL) |
| 1084 | { |
| 1085 | OS_MutexPend(IPMutex); |
| 1086 | frameOut = FrameSendTail; |
| 1087 | if(frameOut) |
| 1088 | FrameRemove(&FrameSendHead, &FrameSendTail, frameOut); |
| 1089 | OS_MutexPost(IPMutex); |
| 1090 | if(frameOut) |
| 1091 | { |
| 1092 | Led(7, 4); |
| 1093 | UartPacketSend(frameOut->packet, frameOut->length); |
| 1094 | } |
| 1095 | } |
| 1096 | |
| 1097 | ticks = OS_ThreadTime(); |
| 1098 | if(ticks - ticksLast > 100) |
| 1099 | { |
| 1100 | IPTick(); |
| 1101 | ticksLast = ticks; |
| 1102 | } |
| 1103 | } |
| 1104 | } |
| 1105 | #endif |
| 1106 | |
| 1107 | |
| 1108 | uint8 *MyPacketGet(void) |
| 1109 | { |
| 1110 | return (uint8*)IPFrameGet(FRAME_COUNT_RCV); |
| 1111 | } |
| 1112 | |
| 1113 | |
| 1114 | //Set FrameSendFunction only if single threaded |
| 1115 | void IPInit(IPFuncPtr frameSendFunction, uint8 macAddress[6], char name[6]) |
| 1116 | { |
| 1117 | int i; |
| 1118 | IPFrame *frame; |
| 1119 | |
| 1120 | if(macAddress) |
| 1121 | memcpy(ethernetAddressPlasma, macAddress, 6); |
| 1122 | if(name) |
| 1123 | memcpy(dhcpOptions+18, name, 6); |
| 1124 | FrameSendFunc = frameSendFunction; |
| 1125 | IPMutex = OS_MutexCreate("IPSem"); |
| 1126 | IPMQueue = OS_MQueueCreate("IPMQ", FRAME_COUNT*2, 32); |
| 1127 | for(i = 0; i < FRAME_COUNT; ++i) |
| 1128 | { |
| 1129 | frame = (IPFrame*)malloc(sizeof(IPFrame)); |
| 1130 | memset(frame, 0, sizeof(IPFrame)); |
| 1131 | frame->next = FrameFreeHead; |
| 1132 | frame->prev = NULL; |
| 1133 | FrameFreeHead = frame; |
| 1134 | } |
| 1135 | FrameFreeCount = FRAME_COUNT; |
| 1136 | #ifndef WIN32 |
| 1137 | UartPacketConfig(MyPacketGet, PACKET_SIZE, IPMQueue); |
| 1138 | if(frameSendFunction == NULL) |
| 1139 | IPThread = OS_ThreadCreate("TCP/IP", IPMainThread, NULL, 240, 6000); |
| 1140 | #endif |
| 1141 | IPDhcp(NULL, 360, 1); //Send DHCP request |
| 1142 | } |
| 1143 | |
| 1144 | |
| 1145 | //To open a socket for listen set ipAddress to 0 |
| 1146 | IPSocket *IPOpen(IPMode_e mode, uint32 ipAddress, uint32 port, IPFuncPtr funcPtr) |
| 1147 | { |
| 1148 | IPSocket *socket; |
| 1149 | uint8 *ptrSend, *ptrRcv; |
| 1150 | IPFrame *frame; |
| 1151 | static int portSource=0x1007; |
| 1152 | |
| 1153 | socket = (IPSocket*)malloc(sizeof(IPSocket)); |
| 1154 | if(socket == NULL) |
| 1155 | return socket; |
| 1156 | memset(socket, 0, sizeof(IPSocket)); |
| 1157 | socket->prev = NULL; |
| 1158 | socket->state = IP_LISTEN; |
| 1159 | socket->timeout = 0; |
| 1160 | socket->timeoutReset = SOCKET_TIMEOUT; |
| 1161 | socket->frameReadHead = NULL; |
| 1162 | socket->frameReadTail = NULL; |
| 1163 | socket->readOffset = 0; |
| 1164 | socket->funcPtr = funcPtr; |
| 1165 | socket->userData = 0; |
| 1166 | socket->userFunc = NULL; |
| 1167 | socket->userPtr = NULL; |
| 1168 | socket->seqWindow = 2048; |
| 1169 | ptrSend = socket->headerSend; |
| 1170 | ptrRcv = socket->headerRcv; |
| 1171 | |
| 1172 | if(ipAddress == 0) |
| 1173 | { |
| 1174 | //Setup listing port |
| 1175 | socket->headerRcv[TCP_DEST_PORT] = (uint8)(port >> 8); |
| 1176 | socket->headerRcv[TCP_DEST_PORT+1] = (uint8)port; |
| 1177 | } |
| 1178 | else |
| 1179 | { |
| 1180 | //Setup sending packet |
| 1181 | memset(ptrSend, 0, UDP_LENGTH); |
| 1182 | memset(ptrRcv, 0, UDP_LENGTH); |
| 1183 | |
| 1184 | //Setup Ethernet |
| 1185 | if(ipAddress != IPAddressSelf()) |
| 1186 | memcpy(ptrSend+ETHERNET_DEST, ethernetAddressGateway, 6); |
| 1187 | else |
| 1188 | memcpy(ptrSend+ETHERNET_DEST, ethernetAddressPlasma, 6); |
| 1189 | memcpy(ptrSend+ETHERNET_SOURCE, ethernetAddressPlasma, 6); |
| 1190 | ptrSend[ETHERNET_FRAME_TYPE] = 0x08; |
| 1191 | |
| 1192 | //Setup IP |
| 1193 | ptrSend[IP_VERSION_LENGTH] = 0x45; |
| 1194 | ptrSend[IP_TIME_TO_LIVE] = 0x80; |
| 1195 | |
| 1196 | //Setup IP addresses |
| 1197 | memcpy(ptrSend+IP_SOURCE, ipAddressPlasma, 4); |
| 1198 | ptrSend[IP_DEST] = (uint8)(ipAddress >> 24); |
| 1199 | ptrSend[IP_DEST+1] = (uint8)(ipAddress >> 16); |
| 1200 | ptrSend[IP_DEST+2] = (uint8)(ipAddress >> 8); |
| 1201 | ptrSend[IP_DEST+3] = (uint8)ipAddress; |
| 1202 | ptrRcv[IP_SOURCE] = (uint8)(ipAddress >> 24); |
| 1203 | ptrRcv[IP_SOURCE+1] = (uint8)(ipAddress >> 16); |
| 1204 | ptrRcv[IP_SOURCE+2] = (uint8)(ipAddress >> 8); |
| 1205 | ptrRcv[IP_SOURCE+3] = (uint8)ipAddress; |
| 1206 | memcpy(ptrRcv+IP_DEST, ipAddressPlasma, 4); |
| 1207 | |
| 1208 | //Setup ports |
| 1209 | ptrSend[TCP_SOURCE_PORT] = (uint8)(portSource >> 8); |
| 1210 | ptrSend[TCP_SOURCE_PORT+1] = (uint8)portSource; |
| 1211 | ptrSend[TCP_DEST_PORT] = (uint8)(port >> 8); |
| 1212 | ptrSend[TCP_DEST_PORT+1] = (uint8)port; |
| 1213 | ptrRcv[TCP_SOURCE_PORT] = (uint8)(port >> 8); |
| 1214 | ptrRcv[TCP_SOURCE_PORT+1] = (uint8)port; |
| 1215 | ptrRcv[TCP_DEST_PORT] = (uint8)(portSource >> 8); |
| 1216 | ptrRcv[TCP_DEST_PORT+1] = (uint8)portSource; |
| 1217 | ++portSource; |
| 1218 | } |
| 1219 | |
| 1220 | if(mode == IP_MODE_TCP) |
| 1221 | { |
| 1222 | if(ipAddress) |
| 1223 | socket->state = IP_TCP; |
| 1224 | else |
| 1225 | socket->state = IP_LISTEN; |
| 1226 | ptrSend[IP_PROTOCOL] = 0x06; //TCP |
| 1227 | ptrRcv[IP_PROTOCOL] = 0x06; |
| 1228 | } |
| 1229 | else if(mode == IP_MODE_UDP) |
| 1230 | { |
| 1231 | socket->state = IP_UDP; |
| 1232 | ptrSend[IP_PROTOCOL] = 0x11; //UDP |
| 1233 | ptrRcv[IP_PROTOCOL] = 0x11; |
| 1234 | } |
| 1235 | else if(mode == IP_MODE_PING) |
| 1236 | { |
| 1237 | socket->state = IP_PING; |
| 1238 | ptrSend[IP_PROTOCOL] = 0x01; //PING |
| 1239 | memset(ptrSend+PING_TYPE, 0, 8); |
| 1240 | ptrSend[PING_TYPE] = 8; //SEND |
| 1241 | } |
| 1242 | |
| 1243 | //Add socket to linked list |
| 1244 | OS_MutexPend(IPMutex); |
| 1245 | socket->next = SocketHead; |
| 1246 | socket->prev = NULL; |
| 1247 | if(SocketHead) |
| 1248 | SocketHead->prev = socket; |
| 1249 | SocketHead = socket; |
| 1250 | OS_MutexPost(IPMutex); |
| 1251 | |
| 1252 | if(mode == IP_MODE_TCP && ipAddress) |
| 1253 | { |
| 1254 | //Send TCP SYN |
| 1255 | socket->seq = 0x01234567; |
| 1256 | frame = IPFrameGet(0); |
| 1257 | if(frame) |
| 1258 | { |
| 1259 | frame->packet[TCP_FLAGS] = TCP_FLAGS_SYN; |
| 1260 | frame->packet[TCP_DATA] = 2; //maximum segment size = 536 |
| 1261 | frame->packet[TCP_DATA+1] = 4; |
| 1262 | frame->packet[TCP_DATA+2] = 2; |
| 1263 | frame->packet[TCP_DATA+3] = 24; |
| 1264 | TCPSendPacket(socket, frame, TCP_DATA+4); |
| 1265 | ++socket->seq; |
| 1266 | } |
| 1267 | } |
| 1268 | return socket; |
| 1269 | } |
| 1270 | |
| 1271 | |
| 1272 | void IPWriteFlush(IPSocket *socket) |
| 1273 | { |
| 1274 | uint8 *packetOut; |
| 1275 | if(socket->frameSend && socket->state != IP_UDP && |
| 1276 | socket->state != IP_PING) |
| 1277 | { |
| 1278 | packetOut = socket->frameSend->packet; |
| 1279 | packetOut[TCP_FLAGS] = TCP_FLAGS_ACK | TCP_FLAGS_PSH; |
| 1280 | TCPSendPacket(socket, socket->frameSend, TCP_DATA + socket->sendOffset); |
| 1281 | socket->seq += socket->sendOffset; |
| 1282 | socket->frameSend = NULL; |
| 1283 | socket->sendOffset = 0; |
| 1284 | } |
| 1285 | } |
| 1286 | |
| 1287 | |
| 1288 | uint32 IPWrite(IPSocket *socket, const uint8 *buf, uint32 length) |
| 1289 | { |
| 1290 | IPFrame *frameOut; |
| 1291 | uint8 *packetOut; |
| 1292 | uint32 bytes, count=0, tries=0; |
| 1293 | int offset; |
| 1294 | OS_Thread_t *self; |
| 1295 | |
| 1296 | if(socket->timeout) |
| 1297 | socket->timeout = socket->timeoutReset; |
| 1298 | |
| 1299 | #ifdef INCLUDE_FILESYS |
| 1300 | if(socket->fileOut) //override stdout |
| 1301 | return fwrite((char*)buf, 1, length, socket->fileOut); |
| 1302 | #endif |
| 1303 | |
| 1304 | //printf("IPWrite(0x%x, %d)", Socket, Length); |
| 1305 | self = OS_ThreadSelf(); |
| 1306 | while(length) |
| 1307 | { |
| 1308 | //Rate limit output |
| 1309 | if(socket->seq - socket->seqReceived >= SEND_WINDOW) |
| 1310 | { |
| 1311 | //printf("l(%d,%d,%d) ", socket->seq - socket->seqReceived, socket->seq, socket->seqReceived); |
| 1312 | if(self != IPThread && ++tries < 200) |
| 1313 | { |
| 1314 | OS_ThreadSleep(1); |
| 1315 | continue; |
| 1316 | } |
| 1317 | } |
| 1318 | tries = 0; |
| 1319 | while(socket->frameSend == NULL) |
| 1320 | { |
| 1321 | socket->frameSend = IPFrameGet(FRAME_COUNT_SEND); |
| 1322 | socket->sendOffset = 0; |
| 1323 | if(socket->frameSend == NULL) |
| 1324 | { |
| 1325 | //printf("L"); |
| 1326 | if(self == IPThread || ++tries > 200) |
| 1327 | break; |
| 1328 | else |
| 1329 | OS_ThreadSleep(1); |
| 1330 | } |
| 1331 | } |
| 1332 | frameOut = socket->frameSend; |
| 1333 | offset = socket->sendOffset; |
| 1334 | if(frameOut == NULL) |
| 1335 | break; |
| 1336 | packetOut = frameOut->packet; |
| 1337 | |
| 1338 | if(socket->state == IP_PING) |
| 1339 | { |
| 1340 | bytes = length; |
| 1341 | memcpy(packetOut, socket->headerSend, PING_DATA); |
| 1342 | memcpy(packetOut+PING_DATA, buf, bytes); |
| 1343 | IPSendPacket(socket, socket->frameSend, PING_DATA + bytes); |
| 1344 | socket->frameSend = NULL; |
| 1345 | } |
| 1346 | else if(socket->state != IP_UDP) |
| 1347 | { |
| 1348 | bytes = 512 - offset; |
| 1349 | if(bytes > length) |
| 1350 | bytes = length; |
| 1351 | socket->sendOffset += bytes; |
| 1352 | memcpy(packetOut+TCP_DATA+offset, buf, bytes); |
| 1353 | if(socket->sendOffset >= 512) |
| 1354 | IPWriteFlush(socket); |
| 1355 | //if(Socket->seq - Socket->seqReceived > Socket->seqWindow) |
| 1356 | //{ |
| 1357 | // printf("W"); |
| 1358 | // OS_ThreadSleep(10); |
| 1359 | //} |
| 1360 | } |
| 1361 | else //UDP |
| 1362 | { |
| 1363 | bytes = length; |
| 1364 | memcpy(packetOut+UDP_DATA+offset, buf, bytes); |
| 1365 | memcpy(packetOut, socket->headerSend, UDP_LENGTH); |
| 1366 | IPSendPacket(socket, socket->frameSend, UDP_DATA + bytes); |
| 1367 | socket->frameSend = NULL; |
| 1368 | } |
| 1369 | count += bytes; |
| 1370 | buf += bytes; |
| 1371 | length -= bytes; |
| 1372 | } |
| 1373 | return count; |
| 1374 | } |
| 1375 | |
| 1376 | |
| 1377 | uint32 IPRead(IPSocket *socket, uint8 *buf, uint32 length) |
| 1378 | { |
| 1379 | IPFrame *frame, *frame2; |
| 1380 | int count=0, bytes, offset; |
| 1381 | |
| 1382 | #ifdef INCLUDE_FILESYS |
| 1383 | if(socket->fileIn) //override stdin |
| 1384 | { |
| 1385 | bytes = fread(buf, 1, 1, socket->fileIn); |
| 1386 | if(bytes == 0) |
| 1387 | { |
| 1388 | buf[0] = 0; |
| 1389 | fclose(socket->fileIn); |
| 1390 | socket->fileIn = NULL; |
| 1391 | bytes = 1; |
| 1392 | } |
| 1393 | return bytes; |
| 1394 | } |
| 1395 | #endif |
| 1396 | |
| 1397 | if(socket->state == IP_UDP) |
| 1398 | offset = UDP_DATA; |
| 1399 | else |
| 1400 | offset = TCP_DATA; |
| 1401 | |
| 1402 | OS_MutexPend(IPMutex); |
| 1403 | for(frame = socket->frameReadTail; length && frame; ) |
| 1404 | { |
| 1405 | bytes = frame->length - offset - socket->readOffset; |
| 1406 | if(bytes > (int)length) |
| 1407 | bytes = length; |
| 1408 | memcpy(buf, frame->packet + offset + socket->readOffset, bytes); |
| 1409 | buf += bytes; |
| 1410 | socket->readOffset += bytes; |
| 1411 | length -= bytes; |
| 1412 | count += bytes; |
| 1413 | |
| 1414 | //Check if done with packet |
| 1415 | frame2 = frame; |
| 1416 | frame = frame->prev; |
| 1417 | if(socket->readOffset == frame2->length - offset) |
| 1418 | { |
| 1419 | //Remove packet from socket linked list |
| 1420 | socket->readOffset = 0; |
| 1421 | FrameRemove(&socket->frameReadHead, &socket->frameReadTail, frame2); |
| 1422 | socket->ackProcessed += frame2->length - offset; |
| 1423 | if(socket->state == IP_TCP && |
| 1424 | socket->ack - socket->ackProcessed > RECEIVE_WINDOW - 2048) |
| 1425 | { |
| 1426 | //Update receive window for flow control |
| 1427 | frame2->packet[TCP_FLAGS] = TCP_FLAGS_ACK; |
| 1428 | TCPSendPacket(socket, frame2, TCP_DATA); |
| 1429 | } |
| 1430 | else |
| 1431 | FrameFree(frame2); |
| 1432 | } |
| 1433 | } |
| 1434 | OS_MutexPost(IPMutex); |
| 1435 | return count; |
| 1436 | } |
| 1437 | |
| 1438 | |
| 1439 | static void IPClose2(IPSocket *socket) |
| 1440 | { |
| 1441 | IPFrame *frame, *framePrev; |
| 1442 | |
| 1443 | OS_MutexPend(IPMutex); |
| 1444 | |
| 1445 | //Mark packets as don't retransmit |
| 1446 | for(frame = FrameSendHead; frame; frame = frame->next) |
| 1447 | { |
| 1448 | if(frame->socket == socket) |
| 1449 | frame->socket = NULL; |
| 1450 | } |
| 1451 | |
| 1452 | //Remove packets from retransmision list |
| 1453 | for(frame = FrameResendHead; frame; ) |
| 1454 | { |
| 1455 | framePrev = frame; |
| 1456 | frame = frame->next; |
| 1457 | if(framePrev->socket == socket) |
| 1458 | { |
| 1459 | FrameRemove(&FrameResendHead, &FrameResendTail, framePrev); |
| 1460 | FrameFree(framePrev); |
| 1461 | } |
| 1462 | } |
| 1463 | |
| 1464 | //Remove packets from socket read linked list |
| 1465 | for(frame = socket->frameReadHead; frame; ) |
| 1466 | { |
| 1467 | framePrev = frame; |
| 1468 | frame = frame->next; |
| 1469 | FrameRemove(&socket->frameReadHead, &socket->frameReadTail, framePrev); |
| 1470 | FrameFree(framePrev); |
| 1471 | } |
| 1472 | |
| 1473 | //Remove socket |
| 1474 | if(socket->state == IP_CLOSED || socket->state <= IP_UDP) |
| 1475 | { |
| 1476 | if(socket->prev == NULL) |
| 1477 | SocketHead = socket->next; |
| 1478 | else |
| 1479 | socket->prev->next = socket->next; |
| 1480 | if(socket->next) |
| 1481 | socket->next->prev = socket->prev; |
| 1482 | free(socket); |
| 1483 | } |
| 1484 | else |
| 1485 | { |
| 1486 | //Give application 10 seconds to stop using socket |
| 1487 | if(socket->state > IP_UDP) |
| 1488 | socket->state = IP_CLOSED; |
| 1489 | socket->timeout = 10; |
| 1490 | } |
| 1491 | OS_MutexPost(IPMutex); |
| 1492 | } |
| 1493 | |
| 1494 | |
| 1495 | void IPClose(IPSocket *socket) |
| 1496 | { |
| 1497 | IPFrame *frameOut; |
| 1498 | |
| 1499 | IPWriteFlush(socket); |
| 1500 | if(socket->state <= IP_UDP) |
| 1501 | { |
| 1502 | IPClose2(socket); |
| 1503 | return; |
| 1504 | } |
| 1505 | frameOut = IPFrameGet(0); |
| 1506 | if(frameOut == NULL) |
| 1507 | return; |
| 1508 | frameOut->packet[TCP_FLAGS] = TCP_FLAGS_FIN | TCP_FLAGS_ACK; |
| 1509 | TCPSendPacket(socket, frameOut, TCP_DATA); |
| 1510 | ++socket->seq; |
| 1511 | if(socket->state == IP_FIN_CLIENT) |
| 1512 | IPClose2(socket); |
| 1513 | else |
| 1514 | socket->state = IP_FIN_SERVER; |
| 1515 | } |
| 1516 | |
| 1517 | |
| 1518 | void IPPrintf(IPSocket *socket, char *message, |
| 1519 | int arg0, int arg1, int arg2, int arg3) |
| 1520 | { |
| 1521 | char buf[500]; |
| 1522 | if(socket == NULL) |
| 1523 | { |
| 1524 | printf(message, arg0, arg1, arg2, arg3); |
| 1525 | return; |
| 1526 | } |
| 1527 | if(strcmp(message, "%s") == 0) |
| 1528 | IPWrite(socket, (uint8*)arg0, (int)strlen((char*)arg0)); |
| 1529 | else |
| 1530 | { |
| 1531 | sprintf(buf, message, arg0, arg1, arg2, arg3, 0, 0, 0, 0); |
| 1532 | IPWrite(socket, (uint8*)buf, (int)strlen(buf)); |
| 1533 | } |
| 1534 | if(socket->dontFlush == 0 || strstr(message, "\n")) |
| 1535 | IPWriteFlush(socket); |
| 1536 | } |
| 1537 | |
| 1538 | |
| 1539 | void IPTick(void) |
| 1540 | { |
| 1541 | IPFrame *frame, *frame2; |
| 1542 | IPSocket *socket, *socket2; |
| 1543 | unsigned long ticks; |
| 1544 | static unsigned long ticksPrev=0, ticksPrev2=0; |
| 1545 | |
| 1546 | ticks = OS_ThreadTime(); |
| 1547 | #ifdef WIN32 |
| 1548 | ticks = ticksPrev + 100; |
| 1549 | #endif |
| 1550 | if(ticks - ticksPrev >= 95) |
| 1551 | { |
| 1552 | if(IPVerbose && (Seconds % 60) == 0) |
| 1553 | { |
| 1554 | if(FrameFreeCount >= FRAME_COUNT-1) |
| 1555 | printf("T"); |
| 1556 | else |
| 1557 | printf("T(%d)", FrameFreeCount); |
| 1558 | } |
| 1559 | ++Seconds; |
| 1560 | if(--DhcpRetrySeconds <= 0) |
| 1561 | IPDhcp(NULL, 400, 1); //DHCP request |
| 1562 | } |
| 1563 | |
| 1564 | OS_MutexPend(IPMutex); |
| 1565 | |
| 1566 | //Retransmit timeout packets |
| 1567 | for(frame = FrameResendHead; frame; ) |
| 1568 | { |
| 1569 | frame2 = frame; |
| 1570 | frame = frame->next; |
| 1571 | frame2->timeout = (short)(frame2->timeout - (ticks - ticksPrev2)); |
| 1572 | if(--frame2->timeout <= 0) |
| 1573 | { |
| 1574 | if(IPVerbose) |
| 1575 | printf("r"); |
| 1576 | FrameRemove(&FrameResendHead, &FrameResendTail, frame2); |
| 1577 | IPSendFrame(frame2); |
| 1578 | } |
| 1579 | } |
| 1580 | |
| 1581 | if(ticks - ticksPrev >= 95) |
| 1582 | { |
| 1583 | //Close timed out sockets |
| 1584 | for(socket = SocketHead; socket; ) |
| 1585 | { |
| 1586 | socket2 = socket; |
| 1587 | socket = socket->next; |
| 1588 | if(socket2->timeout && --socket2->timeout == 0) |
| 1589 | { |
| 1590 | socket2->timeout = 10; |
| 1591 | if(IPVerbose && socket2->state != IP_CLOSED && |
| 1592 | socket2->state != IP_FIN_SERVER) |
| 1593 | printf("t(%d,%d)", socket2->state, FrameFreeCount); |
| 1594 | if(socket2->state == IP_TCP) |
| 1595 | IPClose(socket2); |
| 1596 | else if(socket2->state == IP_FIN_CLIENT) |
| 1597 | IPClose(socket2); |
| 1598 | else |
| 1599 | IPClose2(socket2); |
| 1600 | } |
| 1601 | } |
| 1602 | ticksPrev = ticks; |
| 1603 | } |
| 1604 | OS_MutexPost(IPMutex); |
| 1605 | ticksPrev2 = ticks; |
| 1606 | } |
| 1607 | |
| 1608 | |
| 1609 | static void DnsCallback(IPSocket *socket) |
| 1610 | { |
| 1611 | uint8 buf[200], *ptr; |
| 1612 | uint32 ipAddress; |
| 1613 | int bytes; |
| 1614 | |
| 1615 | memset(buf, 0, sizeof(buf)); |
| 1616 | bytes = IPRead(socket, buf, sizeof(buf)); |
| 1617 | if(buf[DNS_NUM_ANSWERS_RR+1]) |
| 1618 | { |
| 1619 | for(ptr = buf + DNS_QUESTIONS; ptr + 14 <= buf + bytes; ++ptr) |
| 1620 | { |
| 1621 | if(ptr[0] == 0 && ptr[1] == 1 && ptr[2] == 0 && ptr[3] == 1 && |
| 1622 | ptr[8] == 0 && ptr[9] == 4) |
| 1623 | { |
| 1624 | ipAddress = (ptr[10] << 24) | (ptr[11] << 16) | (ptr[12] << 8) | ptr[13]; |
| 1625 | printf("ipAddress = %d.%d.%d.%d\n", ptr[10], ptr[11], ptr[12], ptr[13]); |
| 1626 | socket->userData = ipAddress; |
| 1627 | if(socket->userFunc) |
| 1628 | { |
| 1629 | socket->userFunc(socket, ipAddress, socket->userPtr); |
| 1630 | } |
| 1631 | break; |
| 1632 | } |
| 1633 | } |
| 1634 | } |
| 1635 | IPClose(socket); |
| 1636 | } |
| 1637 | |
| 1638 | |
| 1639 | void IPResolve(char *name, IPFuncPtr resolvedFunc, void *arg) |
| 1640 | { |
| 1641 | uint8 buf[200], *ptr; |
| 1642 | int length, i; |
| 1643 | IPSocket *socket; |
| 1644 | |
| 1645 | socket = IPOpen(IP_MODE_UDP, ipAddressDns, DNS_PORT, DnsCallback); |
| 1646 | memset(buf, 0, sizeof(buf)); |
| 1647 | buf[DNS_ID+1] = 1; |
| 1648 | buf[DNS_FLAGS] = 1; |
| 1649 | buf[DNS_NUM_QUESTIONS+1] = 1; |
| 1650 | |
| 1651 | //Setup name |
| 1652 | ptr = buf + DNS_QUESTIONS; |
| 1653 | strncpy((char*)ptr+1, name, 100); |
| 1654 | ptr[0] = 1; |
| 1655 | while(ptr[0]) |
| 1656 | { |
| 1657 | for(i = 0; i < 100; ++i) |
| 1658 | { |
| 1659 | if(ptr[i+1] == '.' || ptr[i+1] == 0) |
| 1660 | { |
| 1661 | ptr[0] = (uint8)i; |
| 1662 | ptr += i+1; |
| 1663 | break; |
| 1664 | } |
| 1665 | } |
| 1666 | } |
| 1667 | ++ptr; |
| 1668 | ptr[1] = DNS_QUERY_TYPE_IP; |
| 1669 | ptr[3] = DNS_QUERY_CLASS; |
| 1670 | length = (int)(ptr - buf) + 4; |
| 1671 | if(length < 60) |
| 1672 | length = 60; |
| 1673 | |
| 1674 | socket->userFunc = (IPFuncPtr)resolvedFunc; |
| 1675 | socket->userPtr = arg; |
| 1676 | socket->userData = 0; |
| 1677 | IPWrite(socket, buf, length); |
| 1678 | } |
| 1679 | |
plasma/kernel/uart.c |
| 1 | /*-------------------------------------------------------------------- |
| 2 | * TITLE: Plasma Uart Driver |
| 3 | * AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | * DATE CREATED: 12/31/05 |
| 5 | * FILENAME: uart.c |
| 6 | * PROJECT: Plasma CPU core |
| 7 | * COPYRIGHT: Software placed into the public domain by the author. |
| 8 | * Software 'as is' without warranty. Author liable for nothing. |
| 9 | * DESCRIPTION: |
| 10 | * Plasma Uart Driver |
| 11 | *--------------------------------------------------------------------*/ |
| 12 | #define NO_ELLIPSIS2 |
| 13 | #include "plasma.h" |
| 14 | #include "rtos.h" |
| 15 | |
| 16 | #ifndef NO_PACKETS |
| 17 | #define SUPPORT_DATA_PACKETS |
| 18 | #endif |
| 19 | |
| 20 | #define BUFFER_WRITE_SIZE 128 |
| 21 | #define BUFFER_READ_SIZE 128 |
| 22 | #define BUFFER_PRINTF_SIZE 1024 |
| 23 | #undef UartPrintf |
| 24 | |
| 25 | void UartPrintfCritical(const char *format, |
| 26 | int arg0, int arg1, int arg2, int arg3, |
| 27 | int arg4, int arg5, int arg6, int arg7); |
| 28 | |
| 29 | typedef struct Buffer_s { |
| 30 | uint8 *data; |
| 31 | int size; |
| 32 | volatile int read, write; |
| 33 | volatile int pendingRead, pendingWrite; |
| 34 | OS_Semaphore_t *semaphoreRead, *semaphoreWrite; |
| 35 | } Buffer_t; |
| 36 | |
| 37 | static Buffer_t *WriteBuffer, *ReadBuffer; |
| 38 | static OS_Semaphore_t *SemaphoreUart; |
| 39 | static char PrintfString[BUFFER_PRINTF_SIZE]; //Used in UartPrintf |
| 40 | |
| 41 | #ifdef SUPPORT_DATA_PACKETS |
| 42 | //For packet processing [0xff lengthMSB lengthLSB checksum data] |
| 43 | static PacketGetFunc_t UartPacketGet; |
| 44 | static uint8 *PacketCurrent; |
| 45 | static uint32 UartPacketSize; |
| 46 | static uint32 UartPacketChecksum, Checksum; |
| 47 | static OS_MQueue_t *UartPacketMQueue; |
| 48 | static uint32 PacketBytes, PacketLength; |
| 49 | static uint32 UartPacketOutLength, UartPacketOutByte; |
| 50 | int CountOk, CountError; |
| 51 | #endif |
| 52 | static uint8 *UartPacketOut; |
| 53 | |
| 54 | |
| 55 | /******************************************/ |
| 56 | Buffer_t *BufferCreate(int size) |
| 57 | { |
| 58 | Buffer_t *buffer; |
| 59 | buffer = (Buffer_t*)OS_HeapMalloc(NULL, sizeof(Buffer_t) + size); |
| 60 | if(buffer == NULL) |
| 61 | return NULL; |
| 62 | buffer->data = (uint8*)(buffer + 1); |
| 63 | buffer->read = 0; |
| 64 | buffer->write = 0; |
| 65 | buffer->size = size; |
| 66 | buffer->pendingRead = 0; |
| 67 | buffer->pendingWrite = 0; |
| 68 | buffer->semaphoreRead = OS_SemaphoreCreate("BufferRead", 0); |
| 69 | buffer->semaphoreWrite = OS_SemaphoreCreate("BufferWrite", 0); |
| 70 | return buffer; |
| 71 | } |
| 72 | |
| 73 | |
| 74 | void BufferWrite(Buffer_t *buffer, int value, int pend) |
| 75 | { |
| 76 | int writeNext; |
| 77 | |
| 78 | writeNext = buffer->write + 1; |
| 79 | if(writeNext >= buffer->size) |
| 80 | writeNext = 0; |
| 81 | |
| 82 | //Check if room for value |
| 83 | if(writeNext == buffer->read) |
| 84 | { |
| 85 | if(pend == 0) |
| 86 | return; |
| 87 | ++buffer->pendingWrite; |
| 88 | OS_SemaphorePend(buffer->semaphoreWrite, OS_WAIT_FOREVER); |
| 89 | } |
| 90 | |
| 91 | buffer->data[buffer->write] = (uint8)value; |
| 92 | buffer->write = writeNext; |
| 93 | if(buffer->pendingRead) |
| 94 | { |
| 95 | --buffer->pendingRead; |
| 96 | OS_SemaphorePost(buffer->semaphoreRead); |
| 97 | } |
| 98 | } |
| 99 | |
| 100 | |
| 101 | int BufferRead(Buffer_t *buffer, int pend) |
| 102 | { |
| 103 | int value; |
| 104 | |
| 105 | //Check if empty buffer |
| 106 | if(buffer->read == buffer->write) |
| 107 | { |
| 108 | if(pend == 0) |
| 109 | return 0; |
| 110 | ++buffer->pendingRead; |
| 111 | OS_SemaphorePend(buffer->semaphoreRead, OS_WAIT_FOREVER); |
| 112 | } |
| 113 | |
| 114 | value = buffer->data[buffer->read]; |
| 115 | if(++buffer->read >= buffer->size) |
| 116 | buffer->read = 0; |
| 117 | if(buffer->pendingWrite) |
| 118 | { |
| 119 | --buffer->pendingWrite; |
| 120 | OS_SemaphorePost(buffer->semaphoreWrite); |
| 121 | } |
| 122 | return value; |
| 123 | } |
| 124 | |
| 125 | |
| 126 | /******************************************/ |
| 127 | #ifdef SUPPORT_DATA_PACKETS |
| 128 | static void UartPacketRead(uint32 value) |
| 129 | { |
| 130 | uint32 message[4]; |
| 131 | if(PacketBytes == 0 && value == 0xff) |
| 132 | { |
| 133 | ++PacketBytes; |
| 134 | } |
| 135 | else if(PacketBytes == 1) |
| 136 | { |
| 137 | ++PacketBytes; |
| 138 | PacketLength = value << 8; |
| 139 | } |
| 140 | else if(PacketBytes == 2) |
| 141 | { |
| 142 | ++PacketBytes; |
| 143 | PacketLength |= value; |
| 144 | if(PacketLength <= UartPacketSize) |
| 145 | { |
| 146 | if(PacketCurrent == NULL) |
| 147 | PacketCurrent = UartPacketGet(); |
| 148 | } |
| 149 | else |
| 150 | { |
| 151 | PacketBytes = 0; |
| 152 | } |
| 153 | } |
| 154 | else if(PacketBytes == 3) |
| 155 | { |
| 156 | ++PacketBytes; |
| 157 | UartPacketChecksum = value; |
| 158 | Checksum = 0; |
| 159 | } |
| 160 | else if(PacketBytes >= 4) |
| 161 | { |
| 162 | if(PacketCurrent) |
| 163 | PacketCurrent[PacketBytes - 4] = (uint8)value; |
| 164 | Checksum += value; |
| 165 | ++PacketBytes; |
| 166 | if(PacketBytes - 4 >= PacketLength) |
| 167 | { |
| 168 | if((uint8)Checksum == UartPacketChecksum) |
| 169 | { |
| 170 | //Notify thread that a packet has been received |
| 171 | ++CountOk; |
| 172 | message[0] = 0; |
| 173 | message[1] = (uint32)PacketCurrent; |
| 174 | message[2] = PacketLength; |
| 175 | if(PacketCurrent) |
| 176 | OS_MQueueSend(UartPacketMQueue, message); |
| 177 | PacketCurrent = NULL; |
| 178 | } |
| 179 | else |
| 180 | { |
| 181 | ++CountError; |
| 182 | //printf("E"); |
| 183 | } |
| 184 | PacketBytes = 0; |
| 185 | } |
| 186 | } |
| 187 | } |
| 188 | |
| 189 | |
| 190 | static int UartPacketWrite(void) |
| 191 | { |
| 192 | int value=0, i; |
| 193 | uint32 message[4]; |
| 194 | if(UartPacketOut) |
| 195 | { |
| 196 | if(UartPacketOutByte == 0) |
| 197 | { |
| 198 | value = 0xff; |
| 199 | ++UartPacketOutByte; |
| 200 | } |
| 201 | else if(UartPacketOutByte == 1) |
| 202 | { |
| 203 | value = UartPacketOutLength >> 8; |
| 204 | ++UartPacketOutByte; |
| 205 | } |
| 206 | else if(UartPacketOutByte == 2) |
| 207 | { |
| 208 | value = (uint8)UartPacketOutLength; |
| 209 | ++UartPacketOutByte; |
| 210 | } |
| 211 | else if(UartPacketOutByte == 3) |
| 212 | { |
| 213 | value = 0; |
| 214 | for(i = 0; i < (int)UartPacketOutLength; ++i) |
| 215 | value += UartPacketOut[i]; |
| 216 | value = (uint8)value; |
| 217 | ++UartPacketOutByte; |
| 218 | } |
| 219 | else |
| 220 | { |
| 221 | value = UartPacketOut[UartPacketOutByte - 4]; |
| 222 | ++UartPacketOutByte; |
| 223 | if(UartPacketOutByte - 4 >= UartPacketOutLength) |
| 224 | { |
| 225 | //Notify thread that a packet has been sent |
| 226 | message[0] = 1; |
| 227 | message[1] = (uint32)UartPacketOut; |
| 228 | UartPacketOut = 0; |
| 229 | OS_MQueueSend(UartPacketMQueue, message); |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | return value; |
| 234 | } |
| 235 | #endif |
| 236 | |
| 237 | |
| 238 | static void UartInterrupt(void *arg) |
| 239 | { |
| 240 | uint32 status, value, count=0; |
| 241 | (void)arg; |
| 242 | |
| 243 | status = OS_InterruptStatus(); |
| 244 | while(status & IRQ_UART_READ_AVAILABLE) |
| 245 | { |
| 246 | value = MemoryRead(UART_READ); |
| 247 | #ifdef SUPPORT_DATA_PACKETS |
| 248 | if(UartPacketGet && (value == 0xff || PacketBytes)) |
| 249 | UartPacketRead(value); |
| 250 | else |
| 251 | #endif |
| 252 | BufferWrite(ReadBuffer, value, 0); |
| 253 | status = OS_InterruptStatus(); |
| 254 | if(++count >= 16) |
| 255 | break; |
| 256 | } |
| 257 | while(status & IRQ_UART_WRITE_AVAILABLE) |
| 258 | { |
| 259 | #ifdef SUPPORT_DATA_PACKETS |
| 260 | if(UartPacketOut) |
| 261 | { |
| 262 | value = UartPacketWrite(); |
| 263 | MemoryWrite(UART_WRITE, value); |
| 264 | } else |
| 265 | #endif |
| 266 | if(WriteBuffer->read != WriteBuffer->write) |
| 267 | { |
| 268 | value = BufferRead(WriteBuffer, 0); |
| 269 | MemoryWrite(UART_WRITE, value); |
| 270 | } |
| 271 | else |
| 272 | { |
| 273 | OS_InterruptMaskClear(IRQ_UART_WRITE_AVAILABLE); |
| 274 | break; |
| 275 | } |
| 276 | status = OS_InterruptStatus(); |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | |
| 281 | void UartInit(void) |
| 282 | { |
| 283 | uint32 mask; |
| 284 | |
| 285 | SemaphoreUart = OS_SemaphoreCreate("Uart", 1); |
| 286 | WriteBuffer = BufferCreate(BUFFER_WRITE_SIZE); |
| 287 | ReadBuffer = BufferCreate(BUFFER_READ_SIZE); |
| 288 | |
| 289 | mask = IRQ_UART_READ_AVAILABLE | IRQ_UART_WRITE_AVAILABLE; |
| 290 | OS_InterruptRegister(mask, UartInterrupt); |
| 291 | OS_InterruptMaskSet(IRQ_UART_READ_AVAILABLE); |
| 292 | } |
| 293 | |
| 294 | |
| 295 | void UartWrite(int ch) |
| 296 | { |
| 297 | BufferWrite(WriteBuffer, ch, 1); |
| 298 | OS_InterruptMaskSet(IRQ_UART_WRITE_AVAILABLE); |
| 299 | } |
| 300 | |
| 301 | |
| 302 | uint8 UartRead(void) |
| 303 | { |
| 304 | return (uint8)BufferRead(ReadBuffer, 1); |
| 305 | } |
| 306 | |
| 307 | |
| 308 | void UartWriteData(uint8 *data, int length) |
| 309 | { |
| 310 | OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); |
| 311 | while(length--) |
| 312 | UartWrite(*data++); |
| 313 | OS_SemaphorePost(SemaphoreUart); |
| 314 | } |
| 315 | |
| 316 | |
| 317 | void UartReadData(uint8 *data, int length) |
| 318 | { |
| 319 | OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); |
| 320 | while(length--) |
| 321 | *data++ = UartRead(); |
| 322 | OS_SemaphorePost(SemaphoreUart); |
| 323 | } |
| 324 | |
| 325 | |
| 326 | void UartPrintf(const char *format, |
| 327 | int arg0, int arg1, int arg2, int arg3, |
| 328 | int arg4, int arg5, int arg6, int arg7) |
| 329 | { |
| 330 | uint8 *ptr; |
| 331 | #if 0 |
| 332 | //Check for string "!m#~" to mask print statement |
| 333 | static char moduleLevel[26]; |
| 334 | if(format[0] == '!' && format[3] == '~') |
| 335 | { |
| 336 | int level = format[2] - '5'; |
| 337 | if('a' <= format[1] && format[1] <= 'z') |
| 338 | { |
| 339 | if(level < moduleLevel[format[1] - 'a']) |
| 340 | return; |
| 341 | } |
| 342 | else if('A' <= format[1] && format[1] <= 'Z') |
| 343 | moduleLevel[format[1] - 'A'] = (char)level; |
| 344 | format += 4; |
| 345 | } |
| 346 | #endif |
| 347 | OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); |
| 348 | sprintf(PrintfString, format, arg0, arg1, arg2, arg3, |
| 349 | arg4, arg5, arg6, arg7); |
| 350 | ptr = (uint8*)PrintfString; |
| 351 | while(*ptr) |
| 352 | { |
| 353 | if(*ptr == '\n') |
| 354 | UartWrite('\r'); |
| 355 | #ifdef SUPPORT_DATA_PACKETS |
| 356 | if(*ptr == 0xff) |
| 357 | *ptr = '@'; |
| 358 | #endif |
| 359 | UartWrite(*ptr++); |
| 360 | } |
| 361 | OS_SemaphorePost(SemaphoreUart); |
| 362 | } |
| 363 | |
| 364 | |
| 365 | void UartPrintfPoll(const char *format, |
| 366 | int arg0, int arg1, int arg2, int arg3, |
| 367 | int arg4, int arg5, int arg6, int arg7) |
| 368 | { |
| 369 | uint8 *ptr; |
| 370 | uint32 state; |
| 371 | |
| 372 | if(SemaphoreUart) |
| 373 | OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); |
| 374 | sprintf(PrintfString, format, arg0, arg1, arg2, arg3, |
| 375 | arg4, arg5, arg6, arg7); |
| 376 | ptr = (uint8*)PrintfString; |
| 377 | while(*ptr) |
| 378 | { |
| 379 | while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) |
| 380 | ; |
| 381 | state = OS_CriticalBegin(); |
| 382 | if((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) && |
| 383 | UartPacketOut == NULL) |
| 384 | { |
| 385 | MemoryWrite(UART_WRITE, *ptr++); |
| 386 | } |
| 387 | OS_CriticalEnd(state); |
| 388 | } |
| 389 | if(SemaphoreUart) |
| 390 | OS_SemaphorePost(SemaphoreUart); |
| 391 | } |
| 392 | |
| 393 | |
| 394 | void UartPrintfCritical(const char *format, |
| 395 | int arg0, int arg1, int arg2, int arg3, |
| 396 | int arg4, int arg5, int arg6, int arg7) |
| 397 | { |
| 398 | uint8 *ptr; |
| 399 | uint32 state; |
| 400 | |
| 401 | state = OS_CriticalBegin(); |
| 402 | sprintf(PrintfString, format, arg0, arg1, arg2, arg3, |
| 403 | arg4, arg5, arg6, arg7); |
| 404 | ptr = (uint8*)PrintfString; |
| 405 | while(*ptr) |
| 406 | { |
| 407 | while((MemoryRead(IRQ_STATUS) & IRQ_UART_WRITE_AVAILABLE) == 0) |
| 408 | ; |
| 409 | MemoryWrite(UART_WRITE, *ptr++); |
| 410 | #ifdef SUPPORT_DATA_PACKETS |
| 411 | if(UartPacketOut && UartPacketOutByte - 4 < UartPacketOutLength) |
| 412 | { |
| 413 | ++UartPacketOutByte; |
| 414 | --ptr; |
| 415 | } |
| 416 | #endif |
| 417 | } |
| 418 | memset(PrintfString, 0, sizeof(PrintfString)); |
| 419 | OS_CriticalEnd(state); |
| 420 | } |
| 421 | |
| 422 | |
| 423 | void UartPrintfNull(void) |
| 424 | { |
| 425 | } |
| 426 | |
| 427 | |
| 428 | void UartScanf(const char *format, |
| 429 | int arg0, int arg1, int arg2, int arg3, |
| 430 | int arg4, int arg5, int arg6, int arg7) |
| 431 | { |
| 432 | int index = 0, ch; |
| 433 | OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); |
| 434 | for(;;) |
| 435 | { |
| 436 | ch = UartRead(); |
| 437 | if(ch != '\b' || index) |
| 438 | UartWrite(ch); |
| 439 | if(ch == '\n' || ch == '\r') |
| 440 | break; |
| 441 | else if(ch == '\b') |
| 442 | { |
| 443 | if(index) |
| 444 | { |
| 445 | UartWrite(' '); |
| 446 | UartWrite(ch); |
| 447 | --index; |
| 448 | } |
| 449 | } |
| 450 | else if(index < sizeof(PrintfString)) |
| 451 | PrintfString[index++] = (uint8)ch; |
| 452 | } |
| 453 | UartWrite('\n'); |
| 454 | PrintfString[index] = 0; |
| 455 | sscanf(PrintfString, format, arg0, arg1, arg2, arg3, |
| 456 | arg4, arg5, arg6, arg7); |
| 457 | OS_SemaphorePost(SemaphoreUart); |
| 458 | } |
| 459 | |
| 460 | |
| 461 | #ifdef SUPPORT_DATA_PACKETS |
| 462 | void UartPacketConfig(PacketGetFunc_t PacketGetFunc, |
| 463 | int PacketSize, |
| 464 | OS_MQueue_t *mQueue) |
| 465 | { |
| 466 | UartPacketGet = PacketGetFunc; |
| 467 | UartPacketSize = PacketSize; |
| 468 | UartPacketMQueue = mQueue; |
| 469 | } |
| 470 | |
| 471 | |
| 472 | void UartPacketSend(uint8 *data, int bytes) |
| 473 | { |
| 474 | UartPacketOutByte = 0; |
| 475 | UartPacketOutLength = bytes; |
| 476 | UartPacketOut = data; |
| 477 | OS_InterruptMaskSet(IRQ_UART_WRITE_AVAILABLE); |
| 478 | } |
| 479 | #else |
| 480 | void UartPacketConfig(PacketGetFunc_t PacketGetFunc, |
| 481 | int PacketSize, |
| 482 | OS_MQueue_t *mQueue) |
| 483 | { (void)PacketGetFunc; (void)PacketSize; (void)mQueue; } |
| 484 | |
| 485 | |
| 486 | void UartPacketSend(uint8 *data, int bytes) |
| 487 | { (void)data; (void)bytes; } |
| 488 | #endif |
| 489 | |
| 490 | |
| 491 | void Led(int mask, int value) |
| 492 | { |
| 493 | mask &= 0xff; |
| 494 | MemoryWrite(GPIO0_CLEAR, mask); //clear |
| 495 | MemoryWrite(GPIO0_OUT, value & mask); //set LEDs |
| 496 | } |
| 497 | |
| 498 | |
| 499 | /******************************************/ |
| 500 | int puts(const char *string) |
| 501 | { |
| 502 | uint8 *ptr; |
| 503 | OS_SemaphorePend(SemaphoreUart, OS_WAIT_FOREVER); |
| 504 | ptr = (uint8*)string; |
| 505 | while(*ptr) |
| 506 | { |
| 507 | if(*ptr == '\n') |
| 508 | UartWrite('\r'); |
| 509 | UartWrite(*ptr++); |
| 510 | } |
| 511 | OS_SemaphorePost(SemaphoreUart); |
| 512 | return 0; |
| 513 | } |
| 514 | |
| 515 | |
| 516 | int getch(void) |
| 517 | { |
| 518 | return BufferRead(ReadBuffer, 1); |
| 519 | } |
| 520 | |
| 521 | |
| 522 | int kbhit(void) |
| 523 | { |
| 524 | return ReadBuffer->read != ReadBuffer->write; |
| 525 | } |
| 526 | |
| 527 | |
| 528 | /******************************************/ |
| 529 | #if 0 |
| 530 | int LogArray[100], LogIndex; |
| 531 | void LogWrite(int a) |
| 532 | { |
| 533 | if(LogIndex < sizeof(LogArray)/4) |
| 534 | LogArray[LogIndex++] = a; |
| 535 | } |
| 536 | |
| 537 | void LogDump(void) |
| 538 | { |
| 539 | int i; |
| 540 | for(i = 0; i < LogIndex; ++i) |
| 541 | { |
| 542 | if(LogArray[i] > 0xfff) |
| 543 | UartPrintfCritical("\n", 0,0,0,0,0,0,0,0); |
| 544 | UartPrintfCritical("0x%x ", LogArray[i], 0,0,0,0,0,0,0); |
| 545 | } |
| 546 | LogIndex = 0; |
| 547 | } |
| 548 | #endif |
| 549 | |
plasma/logic/control.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: Controller / Opcode Decoder |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 2/8/01 |
| 5 | -- FILENAME: control.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- NOTE: MIPS(tm) is a registered trademark of MIPS Technologies. |
| 10 | -- MIPS Technologies does not endorse and is not associated with |
| 11 | -- this project. |
| 12 | -- DESCRIPTION: |
| 13 | -- Controls the CPU by decoding the opcode and generating control |
| 14 | -- signals to the rest of the CPU. |
| 15 | -- This entity decodes the MIPS(tm) opcode into a |
| 16 | -- Very-Long-Word-Instruction. |
| 17 | -- The 32-bit opcode is converted to a |
| 18 | -- 6+6+6+16+4+2+4+3+2+2+3+2+4 = 60 bit VLWI opcode. |
| 19 | -- Based on information found in: |
| 20 | -- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich |
| 21 | -- and "The Designer's Guide to VHDL" by Peter J. Ashenden |
| 22 | --------------------------------------------------------------------- |
| 23 | library ieee; |
| 24 | use ieee.std_logic_1164.all; |
| 25 | use work.mlite_pack.all; |
| 26 | |
| 27 | entity control is |
| 28 | port(opcode : in std_logic_vector(31 downto 0); |
| 29 | intr_signal : in std_logic; |
| 30 | rs_index : out std_logic_vector(5 downto 0); |
| 31 | rt_index : out std_logic_vector(5 downto 0); |
| 32 | rd_index : out std_logic_vector(5 downto 0); |
| 33 | imm_out : out std_logic_vector(15 downto 0); |
| 34 | alu_func : out alu_function_type; |
| 35 | shift_func : out shift_function_type; |
| 36 | mult_func : out mult_function_type; |
| 37 | branch_func : out branch_function_type; |
| 38 | a_source_out : out a_source_type; |
| 39 | b_source_out : out b_source_type; |
| 40 | c_source_out : out c_source_type; |
| 41 | pc_source_out: out pc_source_type; |
| 42 | mem_source_out:out mem_source_type; |
| 43 | exception_out: out std_logic); |
| 44 | end; --entity control |
| 45 | |
| 46 | architecture logic of control is |
| 47 | begin |
| 48 | |
| 49 | control_proc: process(opcode, intr_signal) |
| 50 | variable op, func : std_logic_vector(5 downto 0); |
| 51 | variable rs, rt, rd : std_logic_vector(5 downto 0); |
| 52 | variable rtx : std_logic_vector(4 downto 0); |
| 53 | variable imm : std_logic_vector(15 downto 0); |
| 54 | variable alu_function : alu_function_type; |
| 55 | variable shift_function : shift_function_type; |
| 56 | variable mult_function : mult_function_type; |
| 57 | variable a_source : a_source_type; |
| 58 | variable b_source : b_source_type; |
| 59 | variable c_source : c_source_type; |
| 60 | variable pc_source : pc_source_type; |
| 61 | variable branch_function: branch_function_type; |
| 62 | variable mem_source : mem_source_type; |
| 63 | variable is_syscall : std_logic; |
| 64 | begin |
| 65 | alu_function := ALU_NOTHING; |
| 66 | shift_function := SHIFT_NOTHING; |
| 67 | mult_function := MULT_NOTHING; |
| 68 | a_source := A_FROM_REG_SOURCE; |
| 69 | b_source := B_FROM_REG_TARGET; |
| 70 | c_source := C_FROM_NULL; |
| 71 | pc_source := FROM_INC4; |
| 72 | branch_function := BRANCH_EQ; |
| 73 | mem_source := MEM_FETCH; |
| 74 | op := opcode(31 downto 26); |
| 75 | rs := '0' & opcode(25 downto 21); |
| 76 | rt := '0' & opcode(20 downto 16); |
| 77 | rtx := opcode(20 downto 16); |
| 78 | rd := '0' & opcode(15 downto 11); |
| 79 | func := opcode(5 downto 0); |
| 80 | imm := opcode(15 downto 0); |
| 81 | is_syscall := '0'; |
| 82 | |
| 83 | case op is |
| 84 | when "000000" => --SPECIAL |
| 85 | case func is |
| 86 | when "000000" => --SLL r[rd]=r[rt]<<re; |
| 87 | a_source := A_FROM_IMM10_6; |
| 88 | c_source := C_FROM_SHIFT; |
| 89 | shift_function := SHIFT_LEFT_UNSIGNED; |
| 90 | |
| 91 | when "000010" => --SRL r[rd]=u[rt]>>re; |
| 92 | a_source := A_FROM_IMM10_6; |
| 93 | c_source := C_FROM_shift; |
| 94 | shift_function := SHIFT_RIGHT_UNSIGNED; |
| 95 | |
| 96 | when "000011" => --SRA r[rd]=r[rt]>>re; |
| 97 | a_source := A_FROM_IMM10_6; |
| 98 | c_source := C_FROM_SHIFT; |
| 99 | shift_function := SHIFT_RIGHT_SIGNED; |
| 100 | |
| 101 | when "000100" => --SLLV r[rd]=r[rt]<<r[rs]; |
| 102 | c_source := C_FROM_SHIFT; |
| 103 | shift_function := SHIFT_LEFT_UNSIGNED; |
| 104 | |
| 105 | when "000110" => --SRLV r[rd]=u[rt]>>r[rs]; |
| 106 | c_source := C_FROM_SHIFT; |
| 107 | shift_function := SHIFT_RIGHT_UNSIGNED; |
| 108 | |
| 109 | when "000111" => --SRAV r[rd]=r[rt]>>r[rs]; |
| 110 | c_source := C_FROM_SHIFT; |
| 111 | shift_function := SHIFT_RIGHT_SIGNED; |
| 112 | |
| 113 | when "001000" => --JR s->pc_next=r[rs]; |
| 114 | pc_source := FROM_BRANCH; |
| 115 | alu_function := ALU_ADD; |
| 116 | branch_function := BRANCH_YES; |
| 117 | |
| 118 | when "001001" => --JALR r[rd]=s->pc_next; s->pc_next=r[rs]; |
| 119 | c_source := C_FROM_PC_PLUS4; |
| 120 | pc_source := FROM_BRANCH; |
| 121 | alu_function := ALU_ADD; |
| 122 | branch_function := BRANCH_YES; |
| 123 | |
| 124 | --when "001010" => --MOVZ if(!r[rt]) r[rd]=r[rs]; /*IV*/ |
| 125 | --when "001011" => --MOVN if(r[rt]) r[rd]=r[rs]; /*IV*/ |
| 126 | |
| 127 | when "001100" => --SYSCALL |
| 128 | is_syscall := '1'; |
| 129 | |
| 130 | when "001101" => --BREAK s->wakeup=1; |
| 131 | is_syscall := '1'; |
| 132 | |
| 133 | --when "001111" => --SYNC s->wakeup=1; |
| 134 | |
| 135 | when "010000" => --MFHI r[rd]=s->hi; |
| 136 | c_source := C_FROM_MULT; |
| 137 | mult_function := MULT_READ_HI; |
| 138 | |
| 139 | when "010001" => --FTHI s->hi=r[rs]; |
| 140 | mult_function := MULT_WRITE_HI; |
| 141 | |
| 142 | when "010010" => --MFLO r[rd]=s->lo; |
| 143 | c_source := C_FROM_MULT; |
| 144 | mult_function := MULT_READ_LO; |
| 145 | |
| 146 | when "010011" => --MTLO s->lo=r[rs]; |
| 147 | mult_function := MULT_WRITE_LO; |
| 148 | |
| 149 | when "011000" => --MULT s->lo=r[rs]*r[rt]; s->hi=0; |
| 150 | mult_function := MULT_SIGNED_MULT; |
| 151 | |
| 152 | when "011001" => --MULTU s->lo=r[rs]*r[rt]; s->hi=0; |
| 153 | mult_function := MULT_MULT; |
| 154 | |
| 155 | when "011010" => --DIV s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; |
| 156 | mult_function := MULT_SIGNED_DIVIDE; |
| 157 | |
| 158 | when "011011" => --DIVU s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; |
| 159 | mult_function := MULT_DIVIDE; |
| 160 | |
| 161 | when "100000" => --ADD r[rd]=r[rs]+r[rt]; |
| 162 | c_source := C_FROM_ALU; |
| 163 | alu_function := ALU_ADD; |
| 164 | |
| 165 | when "100001" => --ADDU r[rd]=r[rs]+r[rt]; |
| 166 | c_source := C_FROM_ALU; |
| 167 | alu_function := ALU_ADD; |
| 168 | |
| 169 | when "100010" => --SUB r[rd]=r[rs]-r[rt]; |
| 170 | c_source := C_FROM_ALU; |
| 171 | alu_function := ALU_SUBTRACT; |
| 172 | |
| 173 | when "100011" => --SUBU r[rd]=r[rs]-r[rt]; |
| 174 | c_source := C_FROM_ALU; |
| 175 | alu_function := ALU_SUBTRACT; |
| 176 | |
| 177 | when "100100" => --AND r[rd]=r[rs]&r[rt]; |
| 178 | c_source := C_FROM_ALU; |
| 179 | alu_function := ALU_AND; |
| 180 | |
| 181 | when "100101" => --OR r[rd]=r[rs]|r[rt]; |
| 182 | c_source := C_FROM_ALU; |
| 183 | alu_function := ALU_OR; |
| 184 | |
| 185 | when "100110" => --XOR r[rd]=r[rs]^r[rt]; |
| 186 | c_source := C_FROM_ALU; |
| 187 | alu_function := ALU_XOR; |
| 188 | |
| 189 | when "100111" => --NOR r[rd]=~(r[rs]|r[rt]); |
| 190 | c_source := C_FROM_ALU; |
| 191 | alu_function := ALU_NOR; |
| 192 | |
| 193 | when "101010" => --SLT r[rd]=r[rs]<r[rt]; |
| 194 | c_source := C_FROM_ALU; |
| 195 | alu_function := ALU_LESS_THAN_SIGNED; |
| 196 | |
| 197 | when "101011" => --SLTU r[rd]=u[rs]<u[rt]; |
| 198 | c_source := C_FROM_ALU; |
| 199 | alu_function := ALU_LESS_THAN; |
| 200 | |
| 201 | when "101101" => --DADDU r[rd]=r[rs]+u[rt]; |
| 202 | c_source := C_FROM_ALU; |
| 203 | alu_function := ALU_ADD; |
| 204 | |
| 205 | --when "110001" => --TGEU |
| 206 | --when "110010" => --TLT |
| 207 | --when "110011" => --TLTU |
| 208 | --when "110100" => --TEQ |
| 209 | --when "110110" => --TNE |
| 210 | when others => |
| 211 | end case; |
| 212 | |
| 213 | when "000001" => --REGIMM |
| 214 | rt := "000000"; |
| 215 | rd := "011111"; |
| 216 | a_source := A_FROM_PC; |
| 217 | b_source := B_FROM_IMMX4; |
| 218 | alu_function := ALU_ADD; |
| 219 | pc_source := FROM_BRANCH; |
| 220 | branch_function := BRANCH_GTZ; |
| 221 | --if(test) pc=pc+imm*4 |
| 222 | |
| 223 | case rtx is |
| 224 | when "10000" => --BLTZAL r[31]=s->pc_next; branch=r[rs]<0; |
| 225 | c_source := C_FROM_PC_PLUS4; |
| 226 | branch_function := BRANCH_LTZ; |
| 227 | |
| 228 | when "00000" => --BLTZ branch=r[rs]<0; |
| 229 | branch_function := BRANCH_LTZ; |
| 230 | |
| 231 | when "10001" => --BGEZAL r[31]=s->pc_next; branch=r[rs]>=0; |
| 232 | c_source := C_FROM_PC_PLUS4; |
| 233 | branch_function := BRANCH_GEZ; |
| 234 | |
| 235 | when "00001" => --BGEZ branch=r[rs]>=0; |
| 236 | branch_function := BRANCH_GEZ; |
| 237 | |
| 238 | --when "10010" => --BLTZALL r[31]=s->pc_next; lbranch=r[rs]<0; |
| 239 | --when "00010" => --BLTZL lbranch=r[rs]<0; |
| 240 | --when "10011" => --BGEZALL r[31]=s->pc_next; lbranch=r[rs]>=0; |
| 241 | --when "00011" => --BGEZL lbranch=r[rs]>=0; |
| 242 | |
| 243 | when others => |
| 244 | end case; |
| 245 | |
| 246 | when "000011" => --JAL r[31]=s->pc_next; s->pc_next=(s->pc&0xf0000000)|target; |
| 247 | c_source := C_FROM_PC_PLUS4; |
| 248 | rd := "011111"; |
| 249 | pc_source := FROM_OPCODE25_0; |
| 250 | |
| 251 | when "000010" => --J s->pc_next=(s->pc&0xf0000000)|target; |
| 252 | pc_source := FROM_OPCODE25_0; |
| 253 | |
| 254 | when "000100" => --BEQ branch=r[rs]==r[rt]; |
| 255 | a_source := A_FROM_PC; |
| 256 | b_source := B_FROM_IMMX4; |
| 257 | alu_function := ALU_ADD; |
| 258 | pc_source := FROM_BRANCH; |
| 259 | branch_function := BRANCH_EQ; |
| 260 | |
| 261 | when "000101" => --BNE branch=r[rs]!=r[rt]; |
| 262 | a_source := A_FROM_PC; |
| 263 | b_source := B_FROM_IMMX4; |
| 264 | alu_function := ALU_ADD; |
| 265 | pc_source := FROM_BRANCH; |
| 266 | branch_function := BRANCH_NE; |
| 267 | |
| 268 | when "000110" => --BLEZ branch=r[rs]<=0; |
| 269 | a_source := A_FROM_PC; |
| 270 | b_source := b_FROM_IMMX4; |
| 271 | alu_function := ALU_ADD; |
| 272 | pc_source := FROM_BRANCH; |
| 273 | branch_function := BRANCH_LEZ; |
| 274 | |
| 275 | when "000111" => --BGTZ branch=r[rs]>0; |
| 276 | a_source := A_FROM_PC; |
| 277 | b_source := B_FROM_IMMX4; |
| 278 | alu_function := ALU_ADD; |
| 279 | pc_source := FROM_BRANCH; |
| 280 | branch_function := BRANCH_GTZ; |
| 281 | |
| 282 | when "001000" => --ADDI r[rt]=r[rs]+(short)imm; |
| 283 | b_source := B_FROM_SIGNED_IMM; |
| 284 | c_source := C_FROM_ALU; |
| 285 | rd := rt; |
| 286 | alu_function := ALU_ADD; |
| 287 | |
| 288 | when "001001" => --ADDIU u[rt]=u[rs]+(short)imm; |
| 289 | b_source := B_FROM_SIGNED_IMM; |
| 290 | c_source := C_FROM_ALU; |
| 291 | rd := rt; |
| 292 | alu_function := ALU_ADD; |
| 293 | |
| 294 | when "001010" => --SLTI r[rt]=r[rs]<(short)imm; |
| 295 | b_source := B_FROM_SIGNED_IMM; |
| 296 | c_source := C_FROM_ALU; |
| 297 | rd := rt; |
| 298 | alu_function := ALU_LESS_THAN_SIGNED; |
| 299 | |
| 300 | when "001011" => --SLTIU u[rt]=u[rs]<(unsigned long)(short)imm; |
| 301 | b_source := B_FROM_SIGNED_IMM; |
| 302 | c_source := C_FROM_ALU; |
| 303 | rd := rt; |
| 304 | alu_function := ALU_LESS_THAN; |
| 305 | |
| 306 | when "001100" => --ANDI r[rt]=r[rs]&imm; |
| 307 | b_source := B_FROM_IMM; |
| 308 | c_source := C_FROM_ALU; |
| 309 | rd := rt; |
| 310 | alu_function := ALU_AND; |
| 311 | |
| 312 | when "001101" => --ORI r[rt]=r[rs]|imm; |
| 313 | b_source := B_FROM_IMM; |
| 314 | c_source := C_FROM_ALU; |
| 315 | rd := rt; |
| 316 | alu_function := ALU_OR; |
| 317 | |
| 318 | when "001110" => --XORI r[rt]=r[rs]^imm; |
| 319 | b_source := B_FROM_IMM; |
| 320 | c_source := C_FROM_ALU; |
| 321 | rd := rt; |
| 322 | alu_function := ALU_XOR; |
| 323 | |
| 324 | when "001111" => --LUI r[rt]=(imm<<16); |
| 325 | c_source := C_FROM_IMM_SHIFT16; |
| 326 | rd := rt; |
| 327 | |
| 328 | when "010000" => --COP0 |
| 329 | alu_function := ALU_OR; |
| 330 | c_source := C_FROM_ALU; |
| 331 | if opcode(23) = '0' then --move from CP0 |
| 332 | rs := '1' & opcode(15 downto 11); |
| 333 | rt := "000000"; |
| 334 | rd := '0' & opcode(20 downto 16); |
| 335 | else --move to CP0 |
| 336 | rs := "000000"; |
| 337 | rd(5) := '1'; |
| 338 | pc_source := FROM_BRANCH; --delay possible interrupt |
| 339 | branch_function := BRANCH_NO; |
| 340 | end if; |
| 341 | |
| 342 | --when "010001" => --COP1 |
| 343 | --when "010010" => --COP2 |
| 344 | --when "010011" => --COP3 |
| 345 | --when "010100" => --BEQL lbranch=r[rs]==r[rt]; |
| 346 | --when "010101" => --BNEL lbranch=r[rs]!=r[rt]; |
| 347 | --when "010110" => --BLEZL lbranch=r[rs]<=0; |
| 348 | --when "010111" => --BGTZL lbranch=r[rs]>0; |
| 349 | |
| 350 | when "100000" => --LB r[rt]=*(signed char*)ptr; |
| 351 | a_source := A_FROM_REG_SOURCE; |
| 352 | b_source := B_FROM_SIGNED_IMM; |
| 353 | alu_function := ALU_ADD; |
| 354 | rd := rt; |
| 355 | c_source := C_FROM_MEMORY; |
| 356 | mem_source := MEM_READ8S; --address=(short)imm+r[rs]; |
| 357 | |
| 358 | when "100001" => --LH r[rt]=*(signed short*)ptr; |
| 359 | a_source := A_FROM_REG_SOURCE; |
| 360 | b_source := B_FROM_SIGNED_IMM; |
| 361 | alu_function := ALU_ADD; |
| 362 | rd := rt; |
| 363 | c_source := C_FROM_MEMORY; |
| 364 | mem_source := MEM_READ16S; --address=(short)imm+r[rs]; |
| 365 | |
| 366 | when "100010" => --LWL //Not Implemented |
| 367 | a_source := A_FROM_REG_SOURCE; |
| 368 | b_source := B_FROM_SIGNED_IMM; |
| 369 | alu_function := ALU_ADD; |
| 370 | rd := rt; |
| 371 | c_source := C_FROM_MEMORY; |
| 372 | mem_source := MEM_READ32; |
| 373 | |
| 374 | when "100011" => --LW r[rt]=*(long*)ptr; |
| 375 | a_source := A_FROM_REG_SOURCE; |
| 376 | b_source := B_FROM_SIGNED_IMM; |
| 377 | alu_function := ALU_ADD; |
| 378 | rd := rt; |
| 379 | c_source := C_FROM_MEMORY; |
| 380 | mem_source := MEM_READ32; |
| 381 | |
| 382 | when "100100" => --LBU r[rt]=*(unsigned char*)ptr; |
| 383 | a_source := A_FROM_REG_SOURCE; |
| 384 | b_source := B_FROM_SIGNED_IMM; |
| 385 | alu_function := ALU_ADD; |
| 386 | rd := rt; |
| 387 | c_source := C_FROM_MEMORY; |
| 388 | mem_source := MEM_READ8; --address=(short)imm+r[rs]; |
| 389 | |
| 390 | when "100101" => --LHU r[rt]=*(unsigned short*)ptr; |
| 391 | a_source := A_FROM_REG_SOURCE; |
| 392 | b_source := B_FROM_SIGNED_IMM; |
| 393 | alu_function := ALU_ADD; |
| 394 | rd := rt; |
| 395 | c_source := C_FROM_MEMORY; |
| 396 | mem_source := MEM_READ16; --address=(short)imm+r[rs]; |
| 397 | |
| 398 | --when "100110" => --LWR //Not Implemented |
| 399 | |
| 400 | when "101000" => --SB *(char*)ptr=(char)r[rt]; |
| 401 | a_source := A_FROM_REG_SOURCE; |
| 402 | b_source := B_FROM_SIGNED_IMM; |
| 403 | alu_function := ALU_ADD; |
| 404 | mem_source := MEM_WRITE8; --address=(short)imm+r[rs]; |
| 405 | |
| 406 | when "101001" => --SH *(short*)ptr=(short)r[rt]; |
| 407 | a_source := A_FROM_REG_SOURCE; |
| 408 | b_source := B_FROM_SIGNED_IMM; |
| 409 | alu_function := ALU_ADD; |
| 410 | mem_source := MEM_WRITE16; |
| 411 | |
| 412 | when "101010" => --SWL //Not Implemented |
| 413 | a_source := A_FROM_REG_SOURCE; |
| 414 | b_source := B_FROM_SIGNED_IMM; |
| 415 | alu_function := ALU_ADD; |
| 416 | mem_source := MEM_WRITE32; --address=(short)imm+r[rs]; |
| 417 | |
| 418 | when "101011" => --SW *(long*)ptr=r[rt]; |
| 419 | a_source := A_FROM_REG_SOURCE; |
| 420 | b_source := B_FROM_SIGNED_IMM; |
| 421 | alu_function := ALU_ADD; |
| 422 | mem_source := MEM_WRITE32; --address=(short)imm+r[rs]; |
| 423 | |
| 424 | --when "101110" => --SWR //Not Implemented |
| 425 | --when "101111" => --CACHE |
| 426 | --when "110000" => --LL r[rt]=*(long*)ptr; |
| 427 | --when "110001" => --LWC1 |
| 428 | --when "110010" => --LWC2 |
| 429 | --when "110011" => --LWC3 |
| 430 | --when "110101" => --LDC1 |
| 431 | --when "110110" => --LDC2 |
| 432 | --when "110111" => --LDC3 |
| 433 | --when "111000" => --SC *(long*)ptr=r[rt]; r[rt]=1; |
| 434 | --when "111001" => --SWC1 |
| 435 | --when "111010" => --SWC2 |
| 436 | --when "111011" => --SWC3 |
| 437 | --when "111101" => --SDC1 |
| 438 | --when "111110" => --SDC2 |
| 439 | --when "111111" => --SDC3 |
| 440 | when others => |
| 441 | end case; |
| 442 | |
| 443 | if c_source = C_FROM_NULL then |
| 444 | rd := "000000"; |
| 445 | end if; |
| 446 | |
| 447 | if intr_signal = '1' or is_syscall = '1' then |
| 448 | rs := "111111"; --interrupt vector |
| 449 | rt := "000000"; |
| 450 | rd := "101110"; --save PC in EPC |
| 451 | alu_function := ALU_OR; |
| 452 | shift_function := SHIFT_NOTHING; |
| 453 | mult_function := MULT_NOTHING; |
| 454 | branch_function := BRANCH_YES; |
| 455 | a_source := A_FROM_REG_SOURCE; |
| 456 | b_source := B_FROM_REG_TARGET; |
| 457 | c_source := C_FROM_PC; |
| 458 | pc_source := FROM_LBRANCH; |
| 459 | mem_source := MEM_FETCH; |
| 460 | exception_out <= '1'; |
| 461 | else |
| 462 | exception_out <= '0'; |
| 463 | end if; |
| 464 | |
| 465 | rs_index <= rs; |
| 466 | rt_index <= rt; |
| 467 | rd_index <= rd; |
| 468 | imm_out <= imm; |
| 469 | alu_func <= alu_function; |
| 470 | shift_func <= shift_function; |
| 471 | mult_func <= mult_function; |
| 472 | branch_func <= branch_function; |
| 473 | a_source_out <= a_source; |
| 474 | b_source_out <= b_source; |
| 475 | c_source_out <= c_source; |
| 476 | pc_source_out <= pc_source; |
| 477 | mem_source_out <= mem_source; |
| 478 | |
| 479 | end process; |
| 480 | |
| 481 | end; --logic |
plasma/logic/ddr_ctrl.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: DDR SDRAM Interface |
| 3 | -- AUTHORS: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 7/26/07 |
| 5 | -- FILENAME: ddr_ctrl.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Double Data Rate Sychronous Dynamic Random Access Memory Interface |
| 11 | -- |
| 12 | -- For: 64 MB = MT46V32M16, 512Mb, 32Mb x 16 (default) |
| 13 | -- ROW = address(25 downto 13) |
| 14 | -- BANK = address(12 downto 11) |
| 15 | -- COL = address(10 downto 2) |
| 16 | -- |
| 17 | -- Changes are needed for 32 MB = MT46V16M16, 256Mb, 16Mb x 16 |
| 18 | -- ROW = address(24 downto 12) -- 25 ignored |
| 19 | -- BANK = address(11 downto 10) |
| 20 | -- COL = address(9 downto 2) --also change ddr_init.c |
| 21 | -- |
| 22 | -- Changes are needed for 128 MB = MT46V64M16, 1Gb, 64Mb x 16 |
| 23 | -- ROW = address(26 downto 14) |
| 24 | -- BANK = address(13 downto 12) |
| 25 | -- COL = address(11 downto 2) --also change ddr_init.c |
| 26 | -- |
| 27 | -- Requires CAS latency=2; burst size=2. |
| 28 | -- Requires clk changes on rising_edge(clk_2x). |
| 29 | -- Requires active, address, byte_we, data_w stable throughout transfer. |
| 30 | -- DLL mode requires 77MHz. Non-DLL mode runs at 25 MHz. |
| 31 | -- |
| 32 | -- cycle_cnt 777777770000111122223333444455556666777777777777 |
| 33 | -- clk_2x --__--__--__--__--__--__--__--__--__--__--__--__ |
| 34 | -- clk ____----____----____----____----____----____---- |
| 35 | -- SD_CLK ----____----____----____----____----____----____ |
| 36 | -- cmd ____write+++WRITE+++____________________________ |
| 37 | -- SD_DQ ~~~~~~~~~~~~~~uuuullllUUUULLLL~~~~~~~~~~~~~~~~~~ |
| 38 | -- |
| 39 | -- cycle_cnt 777777770000111122223333444455556666777777777777 |
| 40 | -- clk_2x --__--__--__--__--__--__--__--__--__--__--__--__ |
| 41 | -- clk ____----____----____----____----____----____---- |
| 42 | -- SD_CLK ----____----____----____----____----____----____ |
| 43 | -- cmd ____read++++________________________read++++____ |
| 44 | -- SD_DQ ~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~~~ |
| 45 | -- SD_DQnDLL ~~~~~~~~~~~~~~~~~~~~~~~~~~uuuullll~~~~~~~~~~~~~~ |
| 46 | -- pause ____------------------------________------------ |
| 47 | -- |
| 48 | -- Must run DdrInit() to initialize DDR chip. |
| 49 | -- Read Micron DDR SDRAM MT46V32M16 data sheet for more details. |
| 50 | --------------------------------------------------------------------- |
| 51 | library ieee; |
| 52 | use ieee.std_logic_1164.all; |
| 53 | use ieee.std_logic_unsigned.all; |
| 54 | use ieee.std_logic_arith.all; |
| 55 | use work.mlite_pack.all; |
| 56 | |
| 57 | entity ddr_ctrl is |
| 58 | port( |
| 59 | clk : in std_logic; |
| 60 | clk_2x : in std_logic; |
| 61 | reset_in : in std_logic; |
| 62 | |
| 63 | address : in std_logic_vector(25 downto 2); |
| 64 | byte_we : in std_logic_vector(3 downto 0); |
| 65 | data_w : in std_logic_vector(31 downto 0); |
| 66 | data_r : out std_logic_vector(31 downto 0); |
| 67 | active : in std_logic; |
| 68 | no_start : in std_logic; |
| 69 | no_stop : in std_logic; |
| 70 | pause : out std_logic; |
| 71 | |
| 72 | SD_CK_P : out std_logic; --clock_positive |
| 73 | SD_CK_N : out std_logic; --clock_negative |
| 74 | SD_CKE : out std_logic; --clock_enable |
| 75 | |
| 76 | SD_BA : out std_logic_vector(1 downto 0); --bank_address |
| 77 | SD_A : out std_logic_vector(12 downto 0); --address(row or col) |
| 78 | SD_CS : out std_logic; --chip_select |
| 79 | SD_RAS : out std_logic; --row_address_strobe |
| 80 | SD_CAS : out std_logic; --column_address_strobe |
| 81 | SD_WE : out std_logic; --write_enable |
| 82 | |
| 83 | SD_DQ : inout std_logic_vector(15 downto 0); --data |
| 84 | SD_UDM : out std_logic; --upper_byte_enable |
| 85 | SD_UDQS : inout std_logic; --upper_data_strobe |
| 86 | SD_LDM : out std_logic; --low_byte_enable |
| 87 | SD_LDQS : inout std_logic); --low_data_strobe |
| 88 | end; --entity ddr |
| 89 | |
| 90 | architecture logic of ddr_ctrl is |
| 91 | |
| 92 | --Commands for bits RAS & CAS & WE |
| 93 | subtype command_type is std_logic_vector(2 downto 0); |
| 94 | constant COMMAND_LMR : command_type := "000"; |
| 95 | constant COMMAND_AUTO_REFRESH : command_type := "001"; |
| 96 | constant COMMAND_PRECHARGE : command_type := "010"; |
| 97 | constant COMMAND_ACTIVE : command_type := "011"; |
| 98 | constant COMMAND_WRITE : command_type := "100"; |
| 99 | constant COMMAND_READ : command_type := "101"; |
| 100 | constant COMMAND_TERMINATE : command_type := "110"; |
| 101 | constant COMMAND_NOP : command_type := "111"; |
| 102 | |
| 103 | subtype ddr_state_type is std_logic_vector(3 downto 0); |
| 104 | constant STATE_POWER_ON : ddr_state_type := "0000"; |
| 105 | constant STATE_IDLE : ddr_state_type := "0001"; |
| 106 | constant STATE_ROW_ACTIVATE : ddr_state_type := "0010"; |
| 107 | constant STATE_ROW_ACTIVE : ddr_state_type := "0011"; |
| 108 | constant STATE_READ : ddr_state_type := "0100"; |
| 109 | constant STATE_READ2 : ddr_state_type := "0101"; |
| 110 | constant STATE_READ3 : ddr_state_type := "0110"; |
| 111 | constant STATE_PRECHARGE : ddr_state_type := "0111"; |
| 112 | constant STATE_PRECHARGE2 : ddr_state_type := "1000"; |
| 113 | |
| 114 | signal state_prev : ddr_state_type; |
| 115 | signal refresh_cnt : std_logic_vector(7 downto 0); |
| 116 | signal data_write2 : std_logic_vector(47 downto 0); --write pipeline |
| 117 | signal byte_we_reg2 : std_logic_vector(5 downto 0); --write pipeline |
| 118 | signal write_active : std_logic; |
| 119 | signal write_prev : std_logic; |
| 120 | signal cycle_count : std_logic_vector(2 downto 0); --half clocks since op |
| 121 | signal cycle_count2 : std_logic_vector(2 downto 0); --delayed by quarter clock |
| 122 | signal cke_reg : std_logic; |
| 123 | signal clk_p : std_logic; |
| 124 | signal bank_open : std_logic_vector(3 downto 0); |
| 125 | signal data_read : std_logic_vector(31 downto 0); |
| 126 | |
| 127 | begin |
| 128 | ddr_proc: process(clk, clk_p, clk_2x, reset_in, |
| 129 | address, byte_we, data_w, active, no_start, no_stop, |
| 130 | SD_DQ, SD_UDQS, SD_LDQS, |
| 131 | state_prev, refresh_cnt, |
| 132 | byte_we_reg2, data_write2, |
| 133 | cycle_count, cycle_count2, write_prev, |
| 134 | write_active, cke_reg, bank_open, |
| 135 | data_read) |
| 136 | type address_array_type is array(3 downto 0) of std_logic_vector(12 downto 0); |
| 137 | variable address_row : address_array_type; |
| 138 | variable command : std_logic_vector(2 downto 0); --RAS & CAS & WE |
| 139 | variable bank_index : integer; |
| 140 | variable state_current : ddr_state_type; |
| 141 | |
| 142 | begin |
| 143 | |
| 144 | command := COMMAND_NOP; |
| 145 | bank_index := conv_integer(address(12 downto 11)); |
| 146 | state_current := state_prev; |
| 147 | |
| 148 | --DDR state machine to determine state_current and command |
| 149 | case state_prev is |
| 150 | when STATE_POWER_ON => |
| 151 | if active = '1' then |
| 152 | if byte_we /= "0000" then |
| 153 | command := address(6 downto 4); --LMR="000" |
| 154 | else |
| 155 | state_current := STATE_IDLE; --read transistions to STATE_IDLE |
| 156 | end if; |
| 157 | end if; |
| 158 | |
| 159 | when STATE_IDLE => |
| 160 | if refresh_cnt(7) = '1' then |
| 161 | state_current := STATE_PRECHARGE; |
| 162 | command := COMMAND_AUTO_REFRESH; |
| 163 | elsif active = '1' and no_start = '0' then |
| 164 | state_current := STATE_ROW_ACTIVATE; |
| 165 | command := COMMAND_ACTIVE; |
| 166 | end if; |
| 167 | |
| 168 | when STATE_ROW_ACTIVATE => |
| 169 | state_current := STATE_ROW_ACTIVE; |
| 170 | |
| 171 | when STATE_ROW_ACTIVE => |
| 172 | if refresh_cnt(7) = '1' then |
| 173 | if write_prev = '0' then |
| 174 | state_current := STATE_PRECHARGE; |
| 175 | command := COMMAND_PRECHARGE; |
| 176 | end if; |
| 177 | elsif active = '1' and no_start = '0' then |
| 178 | if bank_open(bank_index) = '0' then |
| 179 | state_current := STATE_ROW_ACTIVATE; |
| 180 | command := COMMAND_ACTIVE; |
| 181 | elsif address(25 downto 13) /= address_row(bank_index) then |
| 182 | if write_prev = '0' then |
| 183 | state_current := STATE_PRECHARGE; |
| 184 | command := COMMAND_PRECHARGE; |
| 185 | end if; |
| 186 | else |
| 187 | if byte_we /= "0000" then |
| 188 | command := COMMAND_WRITE; |
| 189 | elsif write_prev = '0' then |
| 190 | state_current := STATE_READ; |
| 191 | command := COMMAND_READ; |
| 192 | end if; |
| 193 | end if; |
| 194 | end if; |
| 195 | |
| 196 | when STATE_READ => |
| 197 | state_current := STATE_READ2; |
| 198 | |
| 199 | when STATE_READ2 => |
| 200 | state_current := STATE_READ3; |
| 201 | |
| 202 | when STATE_READ3 => |
| 203 | if no_stop = '0' then |
| 204 | state_current := STATE_ROW_ACTIVE; |
| 205 | end if; |
| 206 | |
| 207 | when STATE_PRECHARGE => |
| 208 | state_current := STATE_PRECHARGE2; |
| 209 | |
| 210 | when STATE_PRECHARGE2 => |
| 211 | state_current := STATE_IDLE; |
| 212 | |
| 213 | when others => |
| 214 | state_current := STATE_IDLE; |
| 215 | end case; --state_prev |
| 216 | |
| 217 | --rising_edge(clk) domain registers |
| 218 | if reset_in = '1' then |
| 219 | state_prev <= STATE_POWER_ON; |
| 220 | cke_reg <= '0'; |
| 221 | refresh_cnt <= ZERO(7 downto 0); |
| 222 | write_prev <= '0'; |
| 223 | write_active <= '0'; |
| 224 | bank_open <= "0000"; |
| 225 | elsif rising_edge(clk) then |
| 226 | |
| 227 | if active = '1' then |
| 228 | cke_reg <= '1'; |
| 229 | end if; |
| 230 | |
| 231 | if command = COMMAND_WRITE then |
| 232 | write_prev <= '1'; |
| 233 | elsif cycle_count2(2 downto 1) = "11" then |
| 234 | write_prev <= '0'; |
| 235 | end if; |
| 236 | |
| 237 | if command = COMMAND_WRITE then |
| 238 | write_active <= '1'; |
| 239 | elsif cycle_count2 = "100" then |
| 240 | write_active <= '0'; |
| 241 | end if; |
| 242 | |
| 243 | if command = COMMAND_ACTIVE then |
| 244 | bank_open(bank_index) <= '1'; |
| 245 | address_row(bank_index) := address(25 downto 13); |
| 246 | end if; |
| 247 | |
| 248 | if command = COMMAND_PRECHARGE then |
| 249 | bank_open <= "0000"; |
| 250 | end if; |
| 251 | |
| 252 | if command = COMMAND_AUTO_REFRESH then |
| 253 | refresh_cnt <= ZERO(7 downto 0); |
| 254 | else |
| 255 | refresh_cnt <= refresh_cnt + 1; |
| 256 | end if; |
| 257 | |
| 258 | state_prev <= state_current; |
| 259 | |
| 260 | end if; --rising_edge(clk) |
| 261 | |
| 262 | --rising_edge(clk_2x) domain registers |
| 263 | if reset_in = '1' then |
| 264 | cycle_count <= "000"; |
| 265 | elsif rising_edge(clk_2x) then |
| 266 | --Cycle_count |
| 267 | if (command = COMMAND_READ or command = COMMAND_WRITE) and clk = '1' then |
| 268 | cycle_count <= "000"; |
| 269 | elsif cycle_count /= "111" then |
| 270 | cycle_count <= cycle_count + 1; |
| 271 | end if; |
| 272 | |
| 273 | clk_p <= clk; --earlier version of not clk |
| 274 | |
| 275 | --Read data (DLL disabled) |
| 276 | if cycle_count = "100" then |
| 277 | data_read(31 downto 16) <= SD_DQ; --data |
| 278 | elsif cycle_count = "101" then |
| 279 | data_read(15 downto 0) <= SD_DQ; |
| 280 | end if; |
| 281 | end if; |
| 282 | |
| 283 | --falling_edge(clk_2x) domain registers |
| 284 | if reset_in = '1' then |
| 285 | cycle_count2 <= "000"; |
| 286 | data_write2 <= ZERO(15 downto 0) & ZERO; |
| 287 | byte_we_reg2 <= "000000"; |
| 288 | elsif falling_edge(clk_2x) then |
| 289 | cycle_count2 <= cycle_count; |
| 290 | |
| 291 | --Write pipeline |
| 292 | if clk = '0' then |
| 293 | data_write2 <= data_write2(31 downto 16) & data_w; |
| 294 | byte_we_reg2 <= byte_we_reg2(3 downto 2) & byte_we; |
| 295 | else |
| 296 | data_write2(47 downto 16) <= data_write2(31 downto 0); |
| 297 | byte_we_reg2(5 downto 2) <= byte_we_reg2(3 downto 0); |
| 298 | end if; |
| 299 | |
| 300 | --Read data (DLL enabled) |
| 301 | --if cycle_count = "100" then |
| 302 | -- data_read(31 downto 16) <= SD_DQ; --data |
| 303 | --elsif cycle_count = "101" then |
| 304 | -- data_read(15 downto 0) <= SD_DQ; |
| 305 | --end if; |
| 306 | end if; |
| 307 | |
| 308 | data_r <= data_read; |
| 309 | |
| 310 | --Write data |
| 311 | if write_active = '1' then |
| 312 | SD_UDQS <= clk_p; --upper_data_strobe |
| 313 | SD_LDQS <= clk_p; --low_data_strobe |
| 314 | SD_DQ <= data_write2(47 downto 32); --data |
| 315 | SD_UDM <= not byte_we_reg2(5); --upper_byte_enable |
| 316 | SD_LDM <= not byte_we_reg2(4); --low_byte_enable |
| 317 | else |
| 318 | SD_UDQS <= 'Z'; --upper_data_strobe |
| 319 | SD_LDQS <= 'Z'; --low_data_strobe |
| 320 | SD_DQ <= "ZZZZZZZZZZZZZZZZ"; --data |
| 321 | SD_UDM <= 'Z'; |
| 322 | SD_LDM <= 'Z'; |
| 323 | end if; |
| 324 | |
| 325 | --DDR control signals |
| 326 | SD_CK_P <= clk_p; --clock_positive |
| 327 | SD_CK_N <= not clk_p; --clock_negative |
| 328 | SD_CKE <= cke_reg; --clock_enable |
| 329 | |
| 330 | SD_BA <= address(12 downto 11); --bank_address |
| 331 | if command = COMMAND_ACTIVE or state_current = STATE_POWER_ON then |
| 332 | SD_A <= address(25 downto 13); --address row |
| 333 | elsif command = COMMAND_READ or command = COMMAND_WRITE then |
| 334 | SD_A <= "000" & address(10 downto 2) & "0"; --address col |
| 335 | else |
| 336 | SD_A <= "0010000000000"; --PERCHARGE all banks |
| 337 | end if; |
| 338 | |
| 339 | SD_CS <= not cke_reg; --chip_select |
| 340 | SD_RAS <= command(2); --row_address_strobe |
| 341 | SD_CAS <= command(1); --column_address_strobe |
| 342 | SD_WE <= command(0); --write_enable |
| 343 | |
| 344 | if active = '1' and state_current /= STATE_POWER_ON and |
| 345 | command /= COMMAND_WRITE and state_prev /= STATE_READ3 then |
| 346 | pause <= '1'; |
| 347 | else |
| 348 | pause <= '0'; |
| 349 | end if; |
| 350 | |
| 351 | end process; --ddr_proc |
| 352 | |
| 353 | end; --architecture logic |
| 354 | |
plasma/logic/mlite_cpu.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: Plasma CPU core |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 2/15/01 |
| 5 | -- FILENAME: mlite_cpu.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- NOTE: MIPS(tm) and MIPS I(tm) are registered trademarks of MIPS |
| 10 | -- Technologies. MIPS Technologies does not endorse and is not |
| 11 | -- associated with this project. |
| 12 | -- DESCRIPTION: |
| 13 | -- Top level VHDL document that ties the nine other entities together. |
| 14 | -- |
| 15 | -- Executes all MIPS I(tm) opcodes but exceptions and non-aligned |
| 16 | -- memory accesses. Based on information found in: |
| 17 | -- "MIPS RISC Architecture" by Gerry Kane and Joe Heinrich |
| 18 | -- and "The Designer's Guide to VHDL" by Peter J. Ashenden |
| 19 | -- |
| 20 | -- The CPU is implemented as a two or three stage pipeline. |
| 21 | -- An add instruction would take the following steps (see cpu.gif): |
| 22 | -- Stage #0: |
| 23 | -- 1. The "pc_next" entity passes the program counter (PC) to the |
| 24 | -- "mem_ctrl" entity which fetches the opcode from memory. |
| 25 | -- Stage #1: |
| 26 | -- 2. The memory returns the opcode. |
| 27 | -- Stage #2: |
| 28 | -- 3. "Mem_ctrl" passes the opcode to the "control" entity. |
| 29 | -- 4. "Control" converts the 32-bit opcode to a 60-bit VLWI opcode |
| 30 | -- and sends control signals to the other entities. |
| 31 | -- 5. Based on the rs_index and rt_index control signals, "reg_bank" |
| 32 | -- sends the 32-bit reg_source and reg_target to "bus_mux". |
| 33 | -- 6. Based on the a_source and b_source control signals, "bus_mux" |
| 34 | -- multiplexes reg_source onto a_bus and reg_target onto b_bus. |
| 35 | -- Stage #3 (part of stage #2 if using two stage pipeline): |
| 36 | -- 7. Based on the alu_func control signals, "alu" adds the values |
| 37 | -- from a_bus and b_bus and places the result on c_bus. |
| 38 | -- 8. Based on the c_source control signals, "bus_bux" multiplexes |
| 39 | -- c_bus onto reg_dest. |
| 40 | -- 9. Based on the rd_index control signal, "reg_bank" saves |
| 41 | -- reg_dest into the correct register. |
| 42 | -- Stage #3b: |
| 43 | -- 10. Read or write memory if needed. |
| 44 | -- |
| 45 | -- All signals are active high. |
| 46 | -- Here are the signals for writing a character to address 0xffff |
| 47 | -- when using a two stage pipeline: |
| 48 | -- |
| 49 | -- Program: |
| 50 | -- addr value opcode |
| 51 | -- ============================= |
| 52 | -- 3c: 00000000 nop |
| 53 | -- 40: 34040041 li $a0,0x41 |
| 54 | -- 44: 3405ffff li $a1,0xffff |
| 55 | -- 48: a0a40000 sb $a0,0($a1) |
| 56 | -- 4c: 00000000 nop |
| 57 | -- 50: 00000000 nop |
| 58 | -- |
| 59 | -- intr_in mem_pause |
| 60 | -- reset_in byte_we Stages |
| 61 | -- ns address data_w data_r 40 44 48 4c 50 |
| 62 | -- 3600 0 0 00000040 00000000 34040041 0 0 1 |
| 63 | -- 3700 0 0 00000044 00000000 3405FFFF 0 0 2 1 |
| 64 | -- 3800 0 0 00000048 00000000 A0A40000 0 0 2 1 |
| 65 | -- 3900 0 0 0000004C 41414141 00000000 0 0 2 1 |
| 66 | -- 4000 0 0 0000FFFC 41414141 XXXXXX41 1 0 3 2 |
| 67 | -- 4100 0 0 00000050 00000000 00000000 0 0 1 |
| 68 | --------------------------------------------------------------------- |
| 69 | library ieee; |
| 70 | use work.mlite_pack.all; |
| 71 | use ieee.std_logic_1164.all; |
| 72 | use ieee.std_logic_unsigned.all; |
| 73 | |
| 74 | entity mlite_cpu is |
| 75 | generic(memory_type : string := "XILINX_16X"; --ALTERA_LPM, or DUAL_PORT_ |
| 76 | mult_type : string := "DEFAULT"; --AREA_OPTIMIZED |
| 77 | shifter_type : string := "DEFAULT"; --AREA_OPTIMIZED |
| 78 | alu_type : string := "DEFAULT"; --AREA_OPTIMIZED |
| 79 | pipeline_stages : natural := 2); --2 or 3 |
| 80 | port(clk : in std_logic; |
| 81 | reset_in : in std_logic; |
| 82 | intr_in : in std_logic; |
| 83 | |
| 84 | address_next : out std_logic_vector(31 downto 2); --for synch ram |
| 85 | byte_we_next : out std_logic_vector(3 downto 0); |
| 86 | |
| 87 | address : out std_logic_vector(31 downto 2); |
| 88 | byte_we : out std_logic_vector(3 downto 0); |
| 89 | data_w : out std_logic_vector(31 downto 0); |
| 90 | data_r : in std_logic_vector(31 downto 0); |
| 91 | mem_pause : in std_logic); |
| 92 | end; --entity mlite_cpu |
| 93 | |
| 94 | architecture logic of mlite_cpu is |
| 95 | --When using a two stage pipeline "sigD <= sig". |
| 96 | --When using a three stage pipeline "sigD <= sig when rising_edge(clk)", |
| 97 | -- so sigD is delayed by one clock cycle. |
| 98 | signal opcode : std_logic_vector(31 downto 0); |
| 99 | signal rs_index : std_logic_vector(5 downto 0); |
| 100 | signal rt_index : std_logic_vector(5 downto 0); |
| 101 | signal rd_index : std_logic_vector(5 downto 0); |
| 102 | signal rd_indexD : std_logic_vector(5 downto 0); |
| 103 | signal reg_source : std_logic_vector(31 downto 0); |
| 104 | signal reg_target : std_logic_vector(31 downto 0); |
| 105 | signal reg_dest : std_logic_vector(31 downto 0); |
| 106 | signal reg_destD : std_logic_vector(31 downto 0); |
| 107 | signal a_bus : std_logic_vector(31 downto 0); |
| 108 | signal a_busD : std_logic_vector(31 downto 0); |
| 109 | signal b_bus : std_logic_vector(31 downto 0); |
| 110 | signal b_busD : std_logic_vector(31 downto 0); |
| 111 | signal c_bus : std_logic_vector(31 downto 0); |
| 112 | signal c_alu : std_logic_vector(31 downto 0); |
| 113 | signal c_shift : std_logic_vector(31 downto 0); |
| 114 | signal c_mult : std_logic_vector(31 downto 0); |
| 115 | signal c_memory : std_logic_vector(31 downto 0); |
| 116 | signal imm : std_logic_vector(15 downto 0); |
| 117 | signal pc_future : std_logic_vector(31 downto 2); |
| 118 | signal pc_current : std_logic_vector(31 downto 2); |
| 119 | signal pc_plus4 : std_logic_vector(31 downto 2); |
| 120 | signal alu_func : alu_function_type; |
| 121 | signal alu_funcD : alu_function_type; |
| 122 | signal shift_func : shift_function_type; |
| 123 | signal shift_funcD : shift_function_type; |
| 124 | signal mult_func : mult_function_type; |
| 125 | signal mult_funcD : mult_function_type; |
| 126 | signal branch_func : branch_function_type; |
| 127 | signal take_branch : std_logic; |
| 128 | signal a_source : a_source_type; |
| 129 | signal b_source : b_source_type; |
| 130 | signal c_source : c_source_type; |
| 131 | signal pc_source : pc_source_type; |
| 132 | signal mem_source : mem_source_type; |
| 133 | signal pause_mult : std_logic; |
| 134 | signal pause_ctrl : std_logic; |
| 135 | signal pause_pipeline : std_logic; |
| 136 | signal pause_any : std_logic; |
| 137 | signal pause_non_ctrl : std_logic; |
| 138 | signal pause_bank : std_logic; |
| 139 | signal nullify_op : std_logic; |
| 140 | signal intr_enable : std_logic; |
| 141 | signal intr_signal : std_logic; |
| 142 | signal exception_sig : std_logic; |
| 143 | signal reset_reg : std_logic_vector(3 downto 0); |
| 144 | signal reset : std_logic; |
| 145 | begin --architecture |
| 146 | |
| 147 | pause_any <= (mem_pause or pause_ctrl) or (pause_mult or pause_pipeline); |
| 148 | pause_non_ctrl <= (mem_pause or pause_mult) or pause_pipeline; |
| 149 | pause_bank <= (mem_pause or pause_ctrl or pause_mult) and not pause_pipeline; |
| 150 | nullify_op <= '1' when (pc_source = FROM_LBRANCH and take_branch = '0') |
| 151 | or intr_signal = '1' or exception_sig = '1' |
| 152 | else '0'; |
| 153 | c_bus <= c_alu or c_shift or c_mult; |
| 154 | reset <= '1' when reset_in = '1' or reset_reg /= "1111" else '0'; |
| 155 | |
| 156 | --synchronize reset and interrupt pins |
| 157 | intr_proc: process(clk, reset_in, reset_reg, intr_in, intr_enable, |
| 158 | pc_source, pc_current, pause_any) |
| 159 | begin |
| 160 | if reset_in = '1' then |
| 161 | reset_reg <= "0000"; |
| 162 | intr_signal <= '0'; |
| 163 | elsif rising_edge(clk) then |
| 164 | if reset_reg /= "1111" then |
| 165 | reset_reg <= reset_reg + 1; |
| 166 | end if; |
| 167 | |
| 168 | --don't try to interrupt a multi-cycle instruction |
| 169 | if pause_any = '0' then |
| 170 | if intr_in = '1' and intr_enable = '1' and |
| 171 | pc_source = FROM_INC4 then |
| 172 | --the epc will contain pc+4 |
| 173 | intr_signal <= '1'; |
| 174 | else |
| 175 | intr_signal <= '0'; |
| 176 | end if; |
| 177 | end if; |
| 178 | |
| 179 | end if; |
| 180 | end process; |
| 181 | |
| 182 | u1_pc_next: pc_next PORT MAP ( |
| 183 | clk => clk, |
| 184 | reset_in => reset, |
| 185 | take_branch => take_branch, |
| 186 | pause_in => pause_any, |
| 187 | pc_new => c_bus(31 downto 2), |
| 188 | opcode25_0 => opcode(25 downto 0), |
| 189 | pc_source => pc_source, |
| 190 | pc_future => pc_future, |
| 191 | pc_current => pc_current, |
| 192 | pc_plus4 => pc_plus4); |
| 193 | |
| 194 | u2_mem_ctrl: mem_ctrl |
| 195 | PORT MAP ( |
| 196 | clk => clk, |
| 197 | reset_in => reset, |
| 198 | pause_in => pause_non_ctrl, |
| 199 | nullify_op => nullify_op, |
| 200 | address_pc => pc_future, |
| 201 | opcode_out => opcode, |
| 202 | |
| 203 | address_in => c_bus, |
| 204 | mem_source => mem_source, |
| 205 | data_write => reg_target, |
| 206 | data_read => c_memory, |
| 207 | pause_out => pause_ctrl, |
| 208 | |
| 209 | address_next => address_next, |
| 210 | byte_we_next => byte_we_next, |
| 211 | |
| 212 | address => address, |
| 213 | byte_we => byte_we, |
| 214 | data_w => data_w, |
| 215 | data_r => data_r); |
| 216 | |
| 217 | u3_control: control PORT MAP ( |
| 218 | opcode => opcode, |
| 219 | intr_signal => intr_signal, |
| 220 | rs_index => rs_index, |
| 221 | rt_index => rt_index, |
| 222 | rd_index => rd_index, |
| 223 | imm_out => imm, |
| 224 | alu_func => alu_func, |
| 225 | shift_func => shift_func, |
| 226 | mult_func => mult_func, |
| 227 | branch_func => branch_func, |
| 228 | a_source_out => a_source, |
| 229 | b_source_out => b_source, |
| 230 | c_source_out => c_source, |
| 231 | pc_source_out=> pc_source, |
| 232 | mem_source_out=> mem_source, |
| 233 | exception_out=> exception_sig); |
| 234 | |
| 235 | u4_reg_bank: reg_bank |
| 236 | generic map(memory_type => memory_type) |
| 237 | port map ( |
| 238 | clk => clk, |
| 239 | reset_in => reset, |
| 240 | pause => pause_bank, |
| 241 | rs_index => rs_index, |
| 242 | rt_index => rt_index, |
| 243 | rd_index => rd_indexD, |
| 244 | reg_source_out => reg_source, |
| 245 | reg_target_out => reg_target, |
| 246 | reg_dest_new => reg_destD, |
| 247 | intr_enable => intr_enable); |
| 248 | |
| 249 | u5_bus_mux: bus_mux port map ( |
| 250 | imm_in => imm, |
| 251 | reg_source => reg_source, |
| 252 | a_mux => a_source, |
| 253 | a_out => a_bus, |
| 254 | |
| 255 | reg_target => reg_target, |
| 256 | b_mux => b_source, |
| 257 | b_out => b_bus, |
| 258 | |
| 259 | c_bus => c_bus, |
| 260 | c_memory => c_memory, |
| 261 | c_pc => pc_current, |
| 262 | c_pc_plus4 => pc_plus4, |
| 263 | c_mux => c_source, |
| 264 | reg_dest_out => reg_dest, |
| 265 | |
| 266 | branch_func => branch_func, |
| 267 | take_branch => take_branch); |
| 268 | |
| 269 | u6_alu: alu |
| 270 | generic map (alu_type => alu_type) |
| 271 | port map ( |
| 272 | a_in => a_busD, |
| 273 | b_in => b_busD, |
| 274 | alu_function => alu_funcD, |
| 275 | c_alu => c_alu); |
| 276 | |
| 277 | u7_shifter: shifter |
| 278 | generic map (shifter_type => shifter_type) |
| 279 | port map ( |
| 280 | value => b_busD, |
| 281 | shift_amount => a_busD(4 downto 0), |
| 282 | shift_func => shift_funcD, |
| 283 | c_shift => c_shift); |
| 284 | |
| 285 | u8_mult: mult |
| 286 | generic map (mult_type => mult_type) |
| 287 | port map ( |
| 288 | clk => clk, |
| 289 | reset_in => reset, |
| 290 | a => a_busD, |
| 291 | b => b_busD, |
| 292 | mult_func => mult_funcD, |
| 293 | c_mult => c_mult, |
| 294 | pause_out => pause_mult); |
| 295 | |
| 296 | pipeline2: if pipeline_stages <= 2 generate |
| 297 | a_busD <= a_bus; |
| 298 | b_busD <= b_bus; |
| 299 | alu_funcD <= alu_func; |
| 300 | shift_funcD <= shift_func; |
| 301 | mult_funcD <= mult_func; |
| 302 | rd_indexD <= rd_index; |
| 303 | reg_destD <= reg_dest; |
| 304 | pause_pipeline <= '0'; |
| 305 | end generate; --pipeline2 |
| 306 | |
| 307 | pipeline3: if pipeline_stages > 2 generate |
| 308 | --When operating in three stage pipeline mode, the following signals |
| 309 | --are delayed by one clock cycle: a_bus, b_bus, alu/shift/mult_func, |
| 310 | --c_source, and rd_index. |
| 311 | u9_pipeline: pipeline port map ( |
| 312 | clk => clk, |
| 313 | reset => reset, |
| 314 | a_bus => a_bus, |
| 315 | a_busD => a_busD, |
| 316 | b_bus => b_bus, |
| 317 | b_busD => b_busD, |
| 318 | alu_func => alu_func, |
| 319 | alu_funcD => alu_funcD, |
| 320 | shift_func => shift_func, |
| 321 | shift_funcD => shift_funcD, |
| 322 | mult_func => mult_func, |
| 323 | mult_funcD => mult_funcD, |
| 324 | reg_dest => reg_dest, |
| 325 | reg_destD => reg_destD, |
| 326 | rd_index => rd_index, |
| 327 | rd_indexD => rd_indexD, |
| 328 | |
| 329 | rs_index => rs_index, |
| 330 | rt_index => rt_index, |
| 331 | pc_source => pc_source, |
| 332 | mem_source => mem_source, |
| 333 | a_source => a_source, |
| 334 | b_source => b_source, |
| 335 | c_source => c_source, |
| 336 | c_bus => c_bus, |
| 337 | pause_any => pause_any, |
| 338 | pause_pipeline => pause_pipeline); |
| 339 | |
| 340 | end generate; --pipeline3 |
| 341 | |
| 342 | end; --architecture logic |
plasma/logic/mlite_pack.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: Plasma Misc. Package |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 2/15/01 |
| 5 | -- FILENAME: mlite_pack.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Data types, constants, and add functions needed for the Plasma CPU. |
| 11 | --------------------------------------------------------------------- |
| 12 | library ieee; |
| 13 | use ieee.std_logic_1164.all; |
| 14 | |
| 15 | package mlite_pack is |
| 16 | constant ZERO : std_logic_vector(31 downto 0) := |
| 17 | "00000000000000000000000000000000"; |
| 18 | constant ONES : std_logic_vector(31 downto 0) := |
| 19 | "11111111111111111111111111111111"; |
| 20 | --make HIGH_Z equal to ZERO if compiler complains |
| 21 | constant HIGH_Z : std_logic_vector(31 downto 0) := |
| 22 | "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ"; |
| 23 | |
| 24 | subtype alu_function_type is std_logic_vector(3 downto 0); |
| 25 | constant ALU_NOTHING : alu_function_type := "0000"; |
| 26 | constant ALU_ADD : alu_function_type := "0001"; |
| 27 | constant ALU_SUBTRACT : alu_function_type := "0010"; |
| 28 | constant ALU_LESS_THAN : alu_function_type := "0011"; |
| 29 | constant ALU_LESS_THAN_SIGNED : alu_function_type := "0100"; |
| 30 | constant ALU_OR : alu_function_type := "0101"; |
| 31 | constant ALU_AND : alu_function_type := "0110"; |
| 32 | constant ALU_XOR : alu_function_type := "0111"; |
| 33 | constant ALU_NOR : alu_function_type := "1000"; |
| 34 | |
| 35 | subtype shift_function_type is std_logic_vector(1 downto 0); |
| 36 | constant SHIFT_NOTHING : shift_function_type := "00"; |
| 37 | constant SHIFT_LEFT_UNSIGNED : shift_function_type := "01"; |
| 38 | constant SHIFT_RIGHT_SIGNED : shift_function_type := "11"; |
| 39 | constant SHIFT_RIGHT_UNSIGNED : shift_function_type := "10"; |
| 40 | |
| 41 | subtype mult_function_type is std_logic_vector(3 downto 0); |
| 42 | constant MULT_NOTHING : mult_function_type := "0000"; |
| 43 | constant MULT_READ_LO : mult_function_type := "0001"; |
| 44 | constant MULT_READ_HI : mult_function_type := "0010"; |
| 45 | constant MULT_WRITE_LO : mult_function_type := "0011"; |
| 46 | constant MULT_WRITE_HI : mult_function_type := "0100"; |
| 47 | constant MULT_MULT : mult_function_type := "0101"; |
| 48 | constant MULT_SIGNED_MULT : mult_function_type := "0110"; |
| 49 | constant MULT_DIVIDE : mult_function_type := "0111"; |
| 50 | constant MULT_SIGNED_DIVIDE : mult_function_type := "1000"; |
| 51 | |
| 52 | subtype a_source_type is std_logic_vector(1 downto 0); |
| 53 | constant A_FROM_REG_SOURCE : a_source_type := "00"; |
| 54 | constant A_FROM_IMM10_6 : a_source_type := "01"; |
| 55 | constant A_FROM_PC : a_source_type := "10"; |
| 56 | |
| 57 | subtype b_source_type is std_logic_vector(1 downto 0); |
| 58 | constant B_FROM_REG_TARGET : b_source_type := "00"; |
| 59 | constant B_FROM_IMM : b_source_type := "01"; |
| 60 | constant B_FROM_SIGNED_IMM : b_source_type := "10"; |
| 61 | constant B_FROM_IMMX4 : b_source_type := "11"; |
| 62 | |
| 63 | subtype c_source_type is std_logic_vector(2 downto 0); |
| 64 | constant C_FROM_NULL : c_source_type := "000"; |
| 65 | constant C_FROM_ALU : c_source_type := "001"; |
| 66 | constant C_FROM_SHIFT : c_source_type := "001"; --same as alu |
| 67 | constant C_FROM_MULT : c_source_type := "001"; --same as alu |
| 68 | constant C_FROM_MEMORY : c_source_type := "010"; |
| 69 | constant C_FROM_PC : c_source_type := "011"; |
| 70 | constant C_FROM_PC_PLUS4 : c_source_type := "100"; |
| 71 | constant C_FROM_IMM_SHIFT16: c_source_type := "101"; |
| 72 | constant C_FROM_REG_SOURCEN: c_source_type := "110"; |
| 73 | |
| 74 | subtype pc_source_type is std_logic_vector(1 downto 0); |
| 75 | constant FROM_INC4 : pc_source_type := "00"; |
| 76 | constant FROM_OPCODE25_0 : pc_source_type := "01"; |
| 77 | constant FROM_BRANCH : pc_source_type := "10"; |
| 78 | constant FROM_LBRANCH : pc_source_type := "11"; |
| 79 | |
| 80 | subtype branch_function_type is std_logic_vector(2 downto 0); |
| 81 | constant BRANCH_LTZ : branch_function_type := "000"; |
| 82 | constant BRANCH_LEZ : branch_function_type := "001"; |
| 83 | constant BRANCH_EQ : branch_function_type := "010"; |
| 84 | constant BRANCH_NE : branch_function_type := "011"; |
| 85 | constant BRANCH_GEZ : branch_function_type := "100"; |
| 86 | constant BRANCH_GTZ : branch_function_type := "101"; |
| 87 | constant BRANCH_YES : branch_function_type := "110"; |
| 88 | constant BRANCH_NO : branch_function_type := "111"; |
| 89 | |
| 90 | -- mode(32=1,16=2,8=3), signed, write |
| 91 | subtype mem_source_type is std_logic_vector(3 downto 0); |
| 92 | constant MEM_FETCH : mem_source_type := "0000"; |
| 93 | constant MEM_READ32 : mem_source_type := "0100"; |
| 94 | constant MEM_WRITE32 : mem_source_type := "0101"; |
| 95 | constant MEM_READ16 : mem_source_type := "1000"; |
| 96 | constant MEM_READ16S : mem_source_type := "1010"; |
| 97 | constant MEM_WRITE16 : mem_source_type := "1001"; |
| 98 | constant MEM_READ8 : mem_source_type := "1100"; |
| 99 | constant MEM_READ8S : mem_source_type := "1110"; |
| 100 | constant MEM_WRITE8 : mem_source_type := "1101"; |
| 101 | |
| 102 | function bv_adder(a : in std_logic_vector; |
| 103 | b : in std_logic_vector; |
| 104 | do_add: in std_logic) return std_logic_vector; |
| 105 | function bv_negate(a : in std_logic_vector) return std_logic_vector; |
| 106 | function bv_increment(a : in std_logic_vector(31 downto 2) |
| 107 | ) return std_logic_vector; |
| 108 | function bv_inc(a : in std_logic_vector |
| 109 | ) return std_logic_vector; |
| 110 | |
| 111 | -- For Altera |
| 112 | COMPONENT lpm_ram_dp |
| 113 | generic ( |
| 114 | LPM_WIDTH : natural; -- MUST be greater than 0 |
| 115 | LPM_WIDTHAD : natural; -- MUST be greater than 0 |
| 116 | LPM_NUMWORDS : natural := 0; |
| 117 | LPM_INDATA : string := "REGISTERED"; |
| 118 | LPM_OUTDATA : string := "REGISTERED"; |
| 119 | LPM_RDADDRESS_CONTROL : string := "REGISTERED"; |
| 120 | LPM_WRADDRESS_CONTROL : string := "REGISTERED"; |
| 121 | LPM_FILE : string := "UNUSED"; |
| 122 | LPM_TYPE : string := "LPM_RAM_DP"; |
| 123 | USE_EAB : string := "OFF"; |
| 124 | INTENDED_DEVICE_FAMILY : string := "UNUSED"; |
| 125 | RDEN_USED : string := "TRUE"; |
| 126 | LPM_HINT : string := "UNUSED"); |
| 127 | port ( |
| 128 | RDCLOCK : in std_logic := '0'; |
| 129 | RDCLKEN : in std_logic := '1'; |
| 130 | RDADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); |
| 131 | RDEN : in std_logic := '1'; |
| 132 | DATA : in std_logic_vector(LPM_WIDTH-1 downto 0); |
| 133 | WRADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); |
| 134 | WREN : in std_logic; |
| 135 | WRCLOCK : in std_logic := '0'; |
| 136 | WRCLKEN : in std_logic := '1'; |
| 137 | Q : out std_logic_vector(LPM_WIDTH-1 downto 0)); |
| 138 | END COMPONENT; |
| 139 | |
| 140 | -- For Altera |
| 141 | component LPM_RAM_DQ |
| 142 | generic ( |
| 143 | LPM_WIDTH : natural; -- MUST be greater than 0 |
| 144 | LPM_WIDTHAD : natural; -- MUST be greater than 0 |
| 145 | LPM_NUMWORDS : natural := 0; |
| 146 | LPM_INDATA : string := "REGISTERED"; |
| 147 | LPM_ADDRESS_CONTROL: string := "REGISTERED"; |
| 148 | LPM_OUTDATA : string := "REGISTERED"; |
| 149 | LPM_FILE : string := "UNUSED"; |
| 150 | LPM_TYPE : string := "LPM_RAM_DQ"; |
| 151 | USE_EAB : string := "OFF"; |
| 152 | INTENDED_DEVICE_FAMILY : string := "UNUSED"; |
| 153 | LPM_HINT : string := "UNUSED"); |
| 154 | port ( |
| 155 | DATA : in std_logic_vector(LPM_WIDTH-1 downto 0); |
| 156 | ADDRESS : in std_logic_vector(LPM_WIDTHAD-1 downto 0); |
| 157 | INCLOCK : in std_logic := '0'; |
| 158 | OUTCLOCK : in std_logic := '0'; |
| 159 | WE : in std_logic; |
| 160 | Q : out std_logic_vector(LPM_WIDTH-1 downto 0)); |
| 161 | end component; |
| 162 | |
| 163 | -- For Xilinx |
| 164 | component RAM16X1D |
| 165 | -- synthesis translate_off |
| 166 | generic (INIT : bit_vector := X"16"); |
| 167 | -- synthesis translate_on |
| 168 | port (DPO : out STD_ULOGIC; |
| 169 | SPO : out STD_ULOGIC; |
| 170 | A0 : in STD_ULOGIC; |
| 171 | A1 : in STD_ULOGIC; |
| 172 | A2 : in STD_ULOGIC; |
| 173 | A3 : in STD_ULOGIC; |
| 174 | D : in STD_ULOGIC; |
| 175 | DPRA0 : in STD_ULOGIC; |
| 176 | DPRA1 : in STD_ULOGIC; |
| 177 | DPRA2 : in STD_ULOGIC; |
| 178 | DPRA3 : in STD_ULOGIC; |
| 179 | WCLK : in STD_ULOGIC; |
| 180 | WE : in STD_ULOGIC); |
| 181 | end component; |
| 182 | |
| 183 | component pc_next |
| 184 | port(clk : in std_logic; |
| 185 | reset_in : in std_logic; |
| 186 | pc_new : in std_logic_vector(31 downto 2); |
| 187 | take_branch : in std_logic; |
| 188 | pause_in : in std_logic; |
| 189 | opcode25_0 : in std_logic_vector(25 downto 0); |
| 190 | pc_source : in pc_source_type; |
| 191 | pc_future : out std_logic_vector(31 downto 2); |
| 192 | pc_current : out std_logic_vector(31 downto 2); |
| 193 | pc_plus4 : out std_logic_vector(31 downto 2)); |
| 194 | end component; |
| 195 | |
| 196 | component mem_ctrl |
| 197 | port(clk : in std_logic; |
| 198 | reset_in : in std_logic; |
| 199 | pause_in : in std_logic; |
| 200 | nullify_op : in std_logic; |
| 201 | address_pc : in std_logic_vector(31 downto 2); |
| 202 | opcode_out : out std_logic_vector(31 downto 0); |
| 203 | |
| 204 | address_in : in std_logic_vector(31 downto 0); |
| 205 | mem_source : in mem_source_type; |
| 206 | data_write : in std_logic_vector(31 downto 0); |
| 207 | data_read : out std_logic_vector(31 downto 0); |
| 208 | pause_out : out std_logic; |
| 209 | |
| 210 | address_next : out std_logic_vector(31 downto 2); |
| 211 | byte_we_next : out std_logic_vector(3 downto 0); |
| 212 | |
| 213 | address : out std_logic_vector(31 downto 2); |
| 214 | byte_we : out std_logic_vector(3 downto 0); |
| 215 | data_w : out std_logic_vector(31 downto 0); |
| 216 | data_r : in std_logic_vector(31 downto 0)); |
| 217 | end component; |
| 218 | |
| 219 | component control |
| 220 | port(opcode : in std_logic_vector(31 downto 0); |
| 221 | intr_signal : in std_logic; |
| 222 | rs_index : out std_logic_vector(5 downto 0); |
| 223 | rt_index : out std_logic_vector(5 downto 0); |
| 224 | rd_index : out std_logic_vector(5 downto 0); |
| 225 | imm_out : out std_logic_vector(15 downto 0); |
| 226 | alu_func : out alu_function_type; |
| 227 | shift_func : out shift_function_type; |
| 228 | mult_func : out mult_function_type; |
| 229 | branch_func : out branch_function_type; |
| 230 | a_source_out : out a_source_type; |
| 231 | b_source_out : out b_source_type; |
| 232 | c_source_out : out c_source_type; |
| 233 | pc_source_out: out pc_source_type; |
| 234 | mem_source_out:out mem_source_type; |
| 235 | exception_out: out std_logic); |
| 236 | end component; |
| 237 | |
| 238 | component reg_bank |
| 239 | generic(memory_type : string := "XILINX_16X"); |
| 240 | port(clk : in std_logic; |
| 241 | reset_in : in std_logic; |
| 242 | pause : in std_logic; |
| 243 | rs_index : in std_logic_vector(5 downto 0); |
| 244 | rt_index : in std_logic_vector(5 downto 0); |
| 245 | rd_index : in std_logic_vector(5 downto 0); |
| 246 | reg_source_out : out std_logic_vector(31 downto 0); |
| 247 | reg_target_out : out std_logic_vector(31 downto 0); |
| 248 | reg_dest_new : in std_logic_vector(31 downto 0); |
| 249 | intr_enable : out std_logic); |
| 250 | end component; |
| 251 | |
| 252 | component bus_mux |
| 253 | port(imm_in : in std_logic_vector(15 downto 0); |
| 254 | reg_source : in std_logic_vector(31 downto 0); |
| 255 | a_mux : in a_source_type; |
| 256 | a_out : out std_logic_vector(31 downto 0); |
| 257 | |
| 258 | reg_target : in std_logic_vector(31 downto 0); |
| 259 | b_mux : in b_source_type; |
| 260 | b_out : out std_logic_vector(31 downto 0); |
| 261 | |
| 262 | c_bus : in std_logic_vector(31 downto 0); |
| 263 | c_memory : in std_logic_vector(31 downto 0); |
| 264 | c_pc : in std_logic_vector(31 downto 2); |
| 265 | c_pc_plus4 : in std_logic_vector(31 downto 2); |
| 266 | c_mux : in c_source_type; |
| 267 | reg_dest_out : out std_logic_vector(31 downto 0); |
| 268 | |
| 269 | branch_func : in branch_function_type; |
| 270 | take_branch : out std_logic); |
| 271 | end component; |
| 272 | |
| 273 | component alu |
| 274 | generic(alu_type : string := "DEFAULT"); |
| 275 | port(a_in : in std_logic_vector(31 downto 0); |
| 276 | b_in : in std_logic_vector(31 downto 0); |
| 277 | alu_function : in alu_function_type; |
| 278 | c_alu : out std_logic_vector(31 downto 0)); |
| 279 | end component; |
| 280 | |
| 281 | component shifter |
| 282 | generic(shifter_type : string := "DEFAULT" ); |
| 283 | port(value : in std_logic_vector(31 downto 0); |
| 284 | shift_amount : in std_logic_vector(4 downto 0); |
| 285 | shift_func : in shift_function_type; |
| 286 | c_shift : out std_logic_vector(31 downto 0)); |
| 287 | end component; |
| 288 | |
| 289 | component mult |
| 290 | generic(mult_type : string := "DEFAULT"); |
| 291 | port(clk : in std_logic; |
| 292 | reset_in : in std_logic; |
| 293 | a, b : in std_logic_vector(31 downto 0); |
| 294 | mult_func : in mult_function_type; |
| 295 | c_mult : out std_logic_vector(31 downto 0); |
| 296 | pause_out : out std_logic); |
| 297 | end component; |
| 298 | |
| 299 | component pipeline |
| 300 | port(clk : in std_logic; |
| 301 | reset : in std_logic; |
| 302 | a_bus : in std_logic_vector(31 downto 0); |
| 303 | a_busD : out std_logic_vector(31 downto 0); |
| 304 | b_bus : in std_logic_vector(31 downto 0); |
| 305 | b_busD : out std_logic_vector(31 downto 0); |
| 306 | alu_func : in alu_function_type; |
| 307 | alu_funcD : out alu_function_type; |
| 308 | shift_func : in shift_function_type; |
| 309 | shift_funcD : out shift_function_type; |
| 310 | mult_func : in mult_function_type; |
| 311 | mult_funcD : out mult_function_type; |
| 312 | reg_dest : in std_logic_vector(31 downto 0); |
| 313 | reg_destD : out std_logic_vector(31 downto 0); |
| 314 | rd_index : in std_logic_vector(5 downto 0); |
| 315 | rd_indexD : out std_logic_vector(5 downto 0); |
| 316 | |
| 317 | rs_index : in std_logic_vector(5 downto 0); |
| 318 | rt_index : in std_logic_vector(5 downto 0); |
| 319 | pc_source : in pc_source_type; |
| 320 | mem_source : in mem_source_type; |
| 321 | a_source : in a_source_type; |
| 322 | b_source : in b_source_type; |
| 323 | c_source : in c_source_type; |
| 324 | c_bus : in std_logic_vector(31 downto 0); |
| 325 | pause_any : in std_logic; |
| 326 | pause_pipeline : out std_logic); |
| 327 | end component; |
| 328 | |
| 329 | component mlite_cpu |
| 330 | generic(memory_type : string := "XILINX_16X"; --ALTERA_LPM, or DUAL_PORT_ |
| 331 | mult_type : string := "DEFAULT"; |
| 332 | shifter_type : string := "DEFAULT"; |
| 333 | alu_type : string := "DEFAULT"; |
| 334 | pipeline_stages : natural := 2); --2 or 3 |
| 335 | port(clk : in std_logic; |
| 336 | reset_in : in std_logic; |
| 337 | intr_in : in std_logic; |
| 338 | |
| 339 | address_next : out std_logic_vector(31 downto 2); --for synch ram |
| 340 | byte_we_next : out std_logic_vector(3 downto 0); |
| 341 | |
| 342 | address : out std_logic_vector(31 downto 2); |
| 343 | byte_we : out std_logic_vector(3 downto 0); |
| 344 | data_w : out std_logic_vector(31 downto 0); |
| 345 | data_r : in std_logic_vector(31 downto 0); |
| 346 | mem_pause : in std_logic); |
| 347 | end component; |
| 348 | |
| 349 | component cache |
| 350 | generic(memory_type : string := "DEFAULT"); |
| 351 | |
| 352 | port(clk : in std_logic; |
| 353 | reset : in std_logic; |
| 354 | address_next : in std_logic_vector(31 downto 2); |
| 355 | byte_we_next : in std_logic_vector(3 downto 0); |
| 356 | cpu_address : in std_logic_vector(31 downto 2); |
| 357 | mem_busy : in std_logic; |
| 358 | |
| 359 | cache_check : out std_logic; --Stage1: address_next in first 2MB DDR |
| 360 | cache_checking : out std_logic; --Stage2: cache checking |
| 361 | cache_miss : out std_logic); --Stage2-3: cache miss |
| 362 | end component; --cache |
| 363 | |
| 364 | component ram |
| 365 | generic(memory_type : string := "DEFAULT"); |
| 366 | port(clk : in std_logic; |
| 367 | enable : in std_logic; |
| 368 | write_byte_enable : in std_logic_vector(3 downto 0); |
| 369 | address : in std_logic_vector(31 downto 2); |
| 370 | data_write : in std_logic_vector(31 downto 0); |
| 371 | data_read : out std_logic_vector(31 downto 0)); |
| 372 | end component; --ram |
| 373 | |
| 374 | component uart |
| 375 | generic(log_file : string := "UNUSED"); |
| 376 | port(clk : in std_logic; |
| 377 | reset : in std_logic; |
| 378 | enable_read : in std_logic; |
| 379 | enable_write : in std_logic; |
| 380 | data_in : in std_logic_vector(7 downto 0); |
| 381 | data_out : out std_logic_vector(7 downto 0); |
| 382 | uart_read : in std_logic; |
| 383 | uart_write : out std_logic; |
| 384 | busy_write : out std_logic; |
| 385 | data_avail : out std_logic); |
| 386 | end component; --uart |
| 387 | |
| 388 | component eth_dma |
| 389 | port(clk : in std_logic; --25 MHz |
| 390 | reset : in std_logic; |
| 391 | enable_eth : in std_logic; |
| 392 | select_eth : in std_logic; |
| 393 | rec_isr : out std_logic; |
| 394 | send_isr : out std_logic; |
| 395 | |
| 396 | address : out std_logic_vector(31 downto 2); --to DDR |
| 397 | byte_we : out std_logic_vector(3 downto 0); |
| 398 | data_write : out std_logic_vector(31 downto 0); |
| 399 | data_read : in std_logic_vector(31 downto 0); |
| 400 | pause_in : in std_logic; |
| 401 | |
| 402 | mem_address : in std_logic_vector(31 downto 2); --from CPU |
| 403 | mem_byte_we : in std_logic_vector(3 downto 0); |
| 404 | data_w : in std_logic_vector(31 downto 0); |
| 405 | pause_out : out std_logic; |
| 406 | |
| 407 | E_RX_CLK : in std_logic; --2.5 MHz receive |
| 408 | E_RX_DV : in std_logic; --data valid |
| 409 | E_RXD : in std_logic_vector(3 downto 0); --receive nibble |
| 410 | E_TX_CLK : in std_logic; --2.5 MHz transmit |
| 411 | E_TX_EN : out std_logic; --transmit enable |
| 412 | E_TXD : out std_logic_vector(3 downto 0)); --transmit nibble |
| 413 | end component; --eth_dma |
| 414 | |
| 415 | component plasma |
| 416 | generic(memory_type : string := "XILINX_X16"; --"DUAL_PORT_" "ALTERA_LPM"; |
| 417 | log_file : string := "UNUSED"; |
| 418 | ethernet : std_logic := '0'; |
| 419 | use_cache : std_logic := '0'); |
| 420 | port(clk : in std_logic; |
| 421 | reset : in std_logic; |
| 422 | uart_write : out std_logic; |
| 423 | uart_read : in std_logic; |
| 424 | |
| 425 | address : out std_logic_vector(31 downto 2); |
| 426 | byte_we : out std_logic_vector(3 downto 0); |
| 427 | data_write : out std_logic_vector(31 downto 0); |
| 428 | data_read : in std_logic_vector(31 downto 0); |
| 429 | mem_pause_in : in std_logic; |
| 430 | no_ddr_start : out std_logic; |
| 431 | no_ddr_stop : out std_logic; |
| 432 | |
| 433 | gpio0_out : out std_logic_vector(31 downto 0); |
| 434 | gpioA_in : in std_logic_vector(31 downto 0)); |
| 435 | end component; --plasma |
| 436 | |
| 437 | component ddr_ctrl |
| 438 | port(clk : in std_logic; |
| 439 | clk_2x : in std_logic; |
| 440 | reset_in : in std_logic; |
| 441 | |
| 442 | address : in std_logic_vector(25 downto 2); |
| 443 | byte_we : in std_logic_vector(3 downto 0); |
| 444 | data_w : in std_logic_vector(31 downto 0); |
| 445 | data_r : out std_logic_vector(31 downto 0); |
| 446 | active : in std_logic; |
| 447 | no_start : in std_logic; |
| 448 | no_stop : in std_logic; |
| 449 | pause : out std_logic; |
| 450 | |
| 451 | SD_CK_P : out std_logic; --clock_positive |
| 452 | SD_CK_N : out std_logic; --clock_negative |
| 453 | SD_CKE : out std_logic; --clock_enable |
| 454 | |
| 455 | SD_BA : out std_logic_vector(1 downto 0); --bank_address |
| 456 | SD_A : out std_logic_vector(12 downto 0); --address(row or col) |
| 457 | SD_CS : out std_logic; --chip_select |
| 458 | SD_RAS : out std_logic; --row_address_strobe |
| 459 | SD_CAS : out std_logic; --column_address_strobe |
| 460 | SD_WE : out std_logic; --write_enable |
| 461 | |
| 462 | SD_DQ : inout std_logic_vector(15 downto 0); --data |
| 463 | SD_UDM : out std_logic; --upper_byte_enable |
| 464 | SD_UDQS : inout std_logic; --upper_data_strobe |
| 465 | SD_LDM : out std_logic; --low_byte_enable |
| 466 | SD_LDQS : inout std_logic); --low_data_strobe |
| 467 | end component; --ddr |
| 468 | |
| 469 | end; --package mlite_pack |
| 470 | |
| 471 | |
| 472 | package body mlite_pack is |
| 473 | |
| 474 | function bv_adder(a : in std_logic_vector; |
| 475 | b : in std_logic_vector; |
| 476 | do_add: in std_logic) return std_logic_vector is |
| 477 | variable carry_in : std_logic; |
| 478 | variable bb : std_logic_vector(a'length-1 downto 0); |
| 479 | variable result : std_logic_vector(a'length downto 0); |
| 480 | begin |
| 481 | if do_add = '1' then |
| 482 | bb := b; |
| 483 | carry_in := '0'; |
| 484 | else |
| 485 | bb := not b; |
| 486 | carry_in := '1'; |
| 487 | end if; |
| 488 | for index in 0 to a'length-1 loop |
| 489 | result(index) := a(index) xor bb(index) xor carry_in; |
| 490 | carry_in := (carry_in and (a(index) or bb(index))) or |
| 491 | (a(index) and bb(index)); |
| 492 | end loop; |
| 493 | result(a'length) := carry_in xnor do_add; |
| 494 | return result; |
| 495 | end; --function |
| 496 | |
| 497 | |
| 498 | function bv_negate(a : in std_logic_vector) return std_logic_vector is |
| 499 | variable carry_in : std_logic; |
| 500 | variable not_a : std_logic_vector(a'length-1 downto 0); |
| 501 | variable result : std_logic_vector(a'length-1 downto 0); |
| 502 | begin |
| 503 | not_a := not a; |
| 504 | carry_in := '1'; |
| 505 | for index in a'reverse_range loop |
| 506 | result(index) := not_a(index) xor carry_in; |
| 507 | carry_in := carry_in and not_a(index); |
| 508 | end loop; |
| 509 | return result; |
| 510 | end; --function |
| 511 | |
| 512 | |
| 513 | function bv_increment(a : in std_logic_vector(31 downto 2) |
| 514 | ) return std_logic_vector is |
| 515 | variable carry_in : std_logic; |
| 516 | variable result : std_logic_vector(31 downto 2); |
| 517 | begin |
| 518 | carry_in := '1'; |
| 519 | for index in 2 to 31 loop |
| 520 | result(index) := a(index) xor carry_in; |
| 521 | carry_in := a(index) and carry_in; |
| 522 | end loop; |
| 523 | return result; |
| 524 | end; --function |
| 525 | |
| 526 | |
| 527 | function bv_inc(a : in std_logic_vector |
| 528 | ) return std_logic_vector is |
| 529 | variable carry_in : std_logic; |
| 530 | variable result : std_logic_vector(a'length-1 downto 0); |
| 531 | begin |
| 532 | carry_in := '1'; |
| 533 | for index in 0 to a'length-1 loop |
| 534 | result(index) := a(index) xor carry_in; |
| 535 | carry_in := a(index) and carry_in; |
| 536 | end loop; |
| 537 | return result; |
| 538 | end; --function |
| 539 | |
| 540 | end; --package body |
| 541 | |
| 542 | |
plasma/logic/plasma_3e.ucf |
| 1 | ##################################################### |
| 2 | ### SPARTAN-3E STARTER KIT BOARD CONSTRAINTS FILE |
| 3 | ##################################################### |
| 4 | # ==== Analog-to-Digital Converter (ADC) ==== |
| 5 | # some connections shared with SPI Flash, DAC, ADC, and AMP |
| 6 | #NET "AD_CONV" LOC = "P11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 7 | # ==== Programmable Gain Amplifier (AMP) ==== |
| 8 | # some connections shared with SPI Flash, DAC, ADC, and AMP |
| 9 | #NET "AMP_CS" LOC = "N7" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 10 | #NET "AMP_DOUT" LOC = "E18" | IOSTANDARD = LVCMOS33 ; |
| 11 | #NET "AMP_SHDN" LOC = "P7" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 12 | # ==== Pushbuttons (BTN) ==== |
| 13 | NET "BTN_EAST" LOC = "H13" | IOSTANDARD = LVTTL | PULLDOWN ; |
| 14 | NET "BTN_NORTH" LOC = "V4" | IOSTANDARD = LVTTL | PULLDOWN ; |
| 15 | NET "BTN_SOUTH" LOC = "K17" | IOSTANDARD = LVTTL | PULLDOWN ; |
| 16 | NET "BTN_WEST" LOC = "D18" | IOSTANDARD = LVTTL | PULLDOWN ; |
| 17 | # ==== Clock inputs (CLK) ==== |
| 18 | NET "CLK_50MHZ" LOC = "C9" | IOSTANDARD = LVCMOS33 ; |
| 19 | # Define clock period for 50 MHz oscillator (40%/60% duty-cycle) |
| 20 | NET "CLK_50MHZ" PERIOD = 20 ns HIGH 40 %; |
| 21 | #NET "CLK_AUX" LOC = "B8" | IOSTANDARD = LVCMOS33 ; |
| 22 | #NET "CLK_SMA" LOC = "A10" | IOSTANDARD = LVCMOS33 ; |
| 23 | # ==== Digital-to-Analog Converter (DAC) ==== |
| 24 | # some connections shared with SPI Flash, DAC, ADC, and AMP |
| 25 | #NET "DAC_CLR" LOC = "P8" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 26 | #NET "DAC_CS" LOC = "N8" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 27 | # ==== 1-Wire Secure EEPROM (DS) |
| 28 | #NET "DS_WIRE" LOC = "U4" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 29 | # ==== Ethernet PHY (E) ==== |
| 30 | #NET "E_COL" LOC = "U6" | IOSTANDARD = LVCMOS33 ; |
| 31 | #NET "E_CRS" LOC = "U13" | IOSTANDARD = LVCMOS33 ; |
| 32 | NET "E_MDC" LOC = "P9" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 33 | NET "E_MDIO" LOC = "U5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 34 | NET "E_RX_CLK" LOC = "V3" | IOSTANDARD = LVCMOS33 ; |
| 35 | NET "E_RX_DV" LOC = "V2" | IOSTANDARD = LVCMOS33 ; |
| 36 | NET "E_RXD<0>" LOC = "V8" | IOSTANDARD = LVCMOS33 ; |
| 37 | NET "E_RXD<1>" LOC = "T11" | IOSTANDARD = LVCMOS33 ; |
| 38 | NET "E_RXD<2>" LOC = "U11" | IOSTANDARD = LVCMOS33 ; |
| 39 | NET "E_RXD<3>" LOC = "V14" | IOSTANDARD = LVCMOS33 ; |
| 40 | #NET "E_RXD<4>" LOC = "U14" | IOSTANDARD = LVCMOS33 ; |
| 41 | NET "E_TX_CLK" LOC = "T7" | IOSTANDARD = LVCMOS33 ; |
| 42 | NET "E_TX_EN" LOC = "P15" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 43 | NET "E_TXD<0>" LOC = "R11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 44 | NET "E_TXD<1>" LOC = "T15" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 45 | NET "E_TXD<2>" LOC = "R5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 46 | NET "E_TXD<3>" LOC = "T5" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 47 | #NET "E_TXD<4>" LOC = "R6" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 48 | # ==== FPGA Configuration Mode, INIT_B Pins (FPGA) ==== |
| 49 | #NET "FPGA_M0" LOC = "M10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 50 | #NET "FPGA_M1" LOC = "V11" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 51 | #NET "FPGA_M2" LOC = "T10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 8 ; |
| 52 | #NET "FPGA_INIT_B" LOC = "T3" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 4 ; |
| 53 | #NET "FPGA_RDWR_B" LOC = "U10" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 4 ; |
| 54 | #NET "FPGA_HSWAP" LOC = "B3" | IOSTANDARD = LVCMOS33 ; |
| 55 | # ==== FX2 Connector (FX2) ==== |
| 56 | #NET "FX2_CLKIN" LOC = "E10" | IOSTANDARD = LVCMOS33 ; |
| 57 | #NET "FX2_CLKIO" LOC = "D9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 58 | #NET "FX2_CLKOUT" LOC = "D10" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 59 | # These four connections are shared with the J1 6-pin accessory header |
| 60 | #NET "FX2_IO<1>" LOC = "B4" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 61 | #NET "FX2_IO<2>" LOC = "A4" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 62 | #NET "FX2_IO<3>" LOC = "D5" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 63 | #NET "FX2_IO<4>" LOC = "C5" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 64 | # These four connections are shared with the J2 6-pin accessory header |
| 65 | #NET "FX2_IO<5>" LOC = "A6" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 66 | #NET "FX2_IO<6>" LOC = "B6" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 67 | #NET "FX2_IO<7>" LOC = "E7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 68 | #NET "FX2_IO<8>" LOC = "F7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 69 | # These four connections are shared with the J4 6-pin accessory header |
| 70 | #NET "FX2_IO<9>" LOC = "D7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 71 | #NET "FX2_IO<10>" LOC = "C7" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 72 | #NET "FX2_IO<11>" LOC = "F8" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 73 | #NET "FX2_IO<12>" LOC = "E8" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 74 | # The discrete LEDs are shared with the following 8 FX2 connections |
| 75 | #NET "FX2_IO<13>" LOC = "F9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 76 | #NET "FX2_IO<14>" LOC = "E9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 77 | #NET "FX2_IO<15>" LOC = "D11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 78 | #NET "FX2_IO<16>" LOC = "C11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 79 | #NET "FX2_IO<17>" LOC = "F11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 80 | #NET "FX2_IO<18>" LOC = "E11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 81 | #NET "FX2_IO<19>" LOC = "E12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 82 | #NET "FX2_IO<20>" LOC = "F12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 83 | #NET "FX2_IO<21>" LOC = "A13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 84 | #NET "FX2_IO<22>" LOC = "B13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 85 | #NET "FX2_IO<23>" LOC = "A14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 86 | #NET "FX2_IO<24>" LOC = "B14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 87 | #NET "FX2_IO<25>" LOC = "C14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 88 | #NET "FX2_IO<26>" LOC = "D14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 89 | #NET "FX2_IO<27>" LOC = "A16" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 90 | #NET "FX2_IO<28>" LOC = "B16" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 91 | #NET "FX2_IO<29>" LOC = "E13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 92 | #NET "FX2_IO<30>" LOC = "C4" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 93 | #NET "FX2_IO<31>" LOC = "B11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 94 | #NET "FX2_IO<32>" LOC = "A11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 95 | #NET "FX2_IO<33>" LOC = "A8" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 96 | #NET "FX2_IO<34>" LOC = "G9" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 97 | #NET "FX2_IP<35>" LOC = "D12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 98 | #NET "FX2_IP<36>" LOC = "C12" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 99 | #NET "FX2_IP<37>" LOC = "A15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 100 | #NET "FX2_IP<38>" LOC = "B15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 101 | #NET "FX2_IO<39>" LOC = "C3" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 102 | #NET "FX2_IP<40>" LOC = "C15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ; |
| 103 | # ==== 6-pin header J1 ==== |
| 104 | # These are shared connections with the FX2 connector |
| 105 | #NET "J1<0>" LOC = "B4" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 106 | #NET "J1<1>" LOC = "A4" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 107 | #NET "J1<2>" LOC = "D5" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 108 | #NET "J1<3>" LOC = "C5" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 109 | # ==== 6-pin header J2 ==== |
| 110 | # These are shared connections with the FX2 connector |
| 111 | #NET "J2<0>" LOC = "A6" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 112 | #NET "J2<1>" LOC = "B6" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 113 | #NET "J2<2>" LOC = "E7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 114 | #NET "J2<3>" LOC = "F7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 115 | # ==== 6-pin header J4 ==== |
| 116 | # These are shared connections with the FX2 connector |
| 117 | #NET "J4<0>" LOC = "D7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 118 | #NET "J4<1>" LOC = "C7" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 119 | #NET "J4<2>" LOC = "F8" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 120 | #NET "J4<3>" LOC = "E8" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 6 ; |
| 121 | # ==== Character LCD (LCD) ==== |
| 122 | #NET "LCD_E" LOC = "M18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 123 | #NET "LCD_RS" LOC = "L18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 124 | #NET "LCD_RW" LOC = "L17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 125 | # LCD data connections are shared with StrataFlash connections SF_D<11:8> |
| 126 | #NET "SF_D<8>" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 127 | #NET "SF_D<9>" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 128 | #NET "SF_D<10>" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 129 | #NET "SF_D<11>" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 130 | # ==== Discrete LEDs (LED) ==== |
| 131 | # These are shared connections with the FX2 connector |
| 132 | NET "LED<0>" LOC = "F12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 133 | NET "LED<1>" LOC = "E12" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 134 | NET "LED<2>" LOC = "E11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 135 | NET "LED<3>" LOC = "F11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 136 | NET "LED<4>" LOC = "C11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 137 | NET "LED<5>" LOC = "D11" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 138 | NET "LED<6>" LOC = "E9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 139 | NET "LED<7>" LOC = "F9" | IOSTANDARD = LVTTL | SLEW = SLOW | DRIVE = 8 ; |
| 140 | # ==== PS/2 Mouse/Keyboard Port (PS2) ==== |
| 141 | NET "PS2_CLK" LOC = "G14" | IOSTANDARD = LVCMOS33 ; |
| 142 | NET "PS2_DATA" LOC = "G13" | IOSTANDARD = LVCMOS33 ; |
| 143 | # ==== Rotary Pushbutton Switch (ROT) ==== |
| 144 | NET "ROT_A" LOC = "K18" | IOSTANDARD = LVTTL | PULLUP ; |
| 145 | NET "ROT_B" LOC = "G18" | IOSTANDARD = LVTTL | PULLUP ; |
| 146 | NET "ROT_CENTER" LOC = "V16" | IOSTANDARD = LVTTL | PULLDOWN ; |
| 147 | # ==== RS-232 Serial Ports (RS232) ==== |
| 148 | NET "RS232_DCE_RXD" LOC = "R7" | IOSTANDARD = LVTTL ; |
| 149 | NET "RS232_DCE_TXD" LOC = "M14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ; |
| 150 | #NET "RS232_DTE_RXD" LOC = "U8" | IOSTANDARD = LVTTL ; |
| 151 | #NET "RS232_DTE_TXD" LOC = "M13" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = SLOW ; |
| 152 | # ==== DDR SDRAM (SD) ==== (I/O Bank 3, VCCO=2.5V) |
| 153 | NET "SD_A<0>" LOC = "T1" | IOSTANDARD = SSTL2_I ; |
| 154 | NET "SD_A<1>" LOC = "R3" | IOSTANDARD = SSTL2_I ; |
| 155 | NET "SD_A<2>" LOC = "R2" | IOSTANDARD = SSTL2_I ; |
| 156 | NET "SD_A<3>" LOC = "P1" | IOSTANDARD = SSTL2_I ; |
| 157 | NET "SD_A<4>" LOC = "F4" | IOSTANDARD = SSTL2_I ; |
| 158 | NET "SD_A<5>" LOC = "H4" | IOSTANDARD = SSTL2_I ; |
| 159 | NET "SD_A<6>" LOC = "H3" | IOSTANDARD = SSTL2_I ; |
| 160 | NET "SD_A<7>" LOC = "H1" | IOSTANDARD = SSTL2_I ; |
| 161 | NET "SD_A<8>" LOC = "H2" | IOSTANDARD = SSTL2_I ; |
| 162 | NET "SD_A<9>" LOC = "N4" | IOSTANDARD = SSTL2_I ; |
| 163 | NET "SD_A<10>" LOC = "T2" | IOSTANDARD = SSTL2_I ; |
| 164 | NET "SD_A<11>" LOC = "N5" | IOSTANDARD = SSTL2_I ; |
| 165 | NET "SD_A<12>" LOC = "P2" | IOSTANDARD = SSTL2_I ; |
| 166 | NET "SD_BA<0>" LOC = "K5" | IOSTANDARD = SSTL2_I ; |
| 167 | NET "SD_BA<1>" LOC = "K6" | IOSTANDARD = SSTL2_I ; |
| 168 | NET "SD_CAS" LOC = "C2" | IOSTANDARD = SSTL2_I ; |
| 169 | NET "SD_CK_N" LOC = "J4" | IOSTANDARD = SSTL2_I ; |
| 170 | NET "SD_CK_P" LOC = "J5" | IOSTANDARD = SSTL2_I ; |
| 171 | NET "SD_CKE" LOC = "K3" | IOSTANDARD = SSTL2_I ; |
| 172 | NET "SD_CS" LOC = "K4" | IOSTANDARD = SSTL2_I ; |
| 173 | NET "SD_DQ<0>" LOC = "L2" | IOSTANDARD = SSTL2_I ; |
| 174 | NET "SD_DQ<1>" LOC = "L1" | IOSTANDARD = SSTL2_I ; |
| 175 | NET "SD_DQ<2>" LOC = "L3" | IOSTANDARD = SSTL2_I ; |
| 176 | NET "SD_DQ<3>" LOC = "L4" | IOSTANDARD = SSTL2_I ; |
| 177 | NET "SD_DQ<4>" LOC = "M3" | IOSTANDARD = SSTL2_I ; |
| 178 | NET "SD_DQ<5>" LOC = "M4" | IOSTANDARD = SSTL2_I ; |
| 179 | NET "SD_DQ<6>" LOC = "M5" | IOSTANDARD = SSTL2_I ; |
| 180 | NET "SD_DQ<7>" LOC = "M6" | IOSTANDARD = SSTL2_I ; |
| 181 | NET "SD_DQ<8>" LOC = "E2" | IOSTANDARD = SSTL2_I ; |
| 182 | NET "SD_DQ<9>" LOC = "E1" | IOSTANDARD = SSTL2_I ; |
| 183 | NET "SD_DQ<10>" LOC = "F1" | IOSTANDARD = SSTL2_I ; |
| 184 | NET "SD_DQ<11>" LOC = "F2" | IOSTANDARD = SSTL2_I ; |
| 185 | NET "SD_DQ<12>" LOC = "G6" | IOSTANDARD = SSTL2_I ; |
| 186 | NET "SD_DQ<13>" LOC = "G5" | IOSTANDARD = SSTL2_I ; |
| 187 | NET "SD_DQ<14>" LOC = "H6" | IOSTANDARD = SSTL2_I ; |
| 188 | NET "SD_DQ<15>" LOC = "H5" | IOSTANDARD = SSTL2_I ; |
| 189 | NET "SD_LDM" LOC = "J2" | IOSTANDARD = SSTL2_I ; |
| 190 | NET "SD_LDQS" LOC = "L6" | IOSTANDARD = SSTL2_I ; |
| 191 | NET "SD_RAS" LOC = "C1" | IOSTANDARD = SSTL2_I ; |
| 192 | NET "SD_UDM" LOC = "J1" | IOSTANDARD = SSTL2_I ; |
| 193 | NET "SD_UDQS" LOC = "G3" | IOSTANDARD = SSTL2_I ; |
| 194 | NET "SD_WE" LOC = "D1" | IOSTANDARD = SSTL2_I ; |
| 195 | # Path to allow connection to top DCM connection |
| 196 | #NET "SD_CK_FB" LOC = "B9" | IOSTANDARD = LVCMOS33 ; |
| 197 | # Prohibit VREF pins |
| 198 | CONFIG PROHIBIT = D2; |
| 199 | CONFIG PROHIBIT = G4; |
| 200 | CONFIG PROHIBIT = J6; |
| 201 | CONFIG PROHIBIT = L5; |
| 202 | CONFIG PROHIBIT = R4; |
| 203 | # ==== Intel StrataFlash Parallel NOR Flash (SF) ==== |
| 204 | NET "SF_A<0>" LOC = "H17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 205 | NET "SF_A<1>" LOC = "J13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 206 | NET "SF_A<2>" LOC = "J12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 207 | NET "SF_A<3>" LOC = "J14" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 208 | NET "SF_A<4>" LOC = "J15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 209 | NET "SF_A<5>" LOC = "J16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 210 | NET "SF_A<6>" LOC = "J17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 211 | NET "SF_A<7>" LOC = "K14" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 212 | NET "SF_A<8>" LOC = "K15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 213 | NET "SF_A<9>" LOC = "K12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 214 | NET "SF_A<10>" LOC = "K13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 215 | NET "SF_A<11>" LOC = "L15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 216 | NET "SF_A<12>" LOC = "L16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 217 | NET "SF_A<13>" LOC = "T18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 218 | NET "SF_A<14>" LOC = "R18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 219 | NET "SF_A<15>" LOC = "T17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 220 | NET "SF_A<16>" LOC = "U18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 221 | NET "SF_A<17>" LOC = "T16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 222 | NET "SF_A<18>" LOC = "U15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 223 | NET "SF_A<19>" LOC = "V15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 224 | NET "SF_A<20>" LOC = "T12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 225 | NET "SF_A<21>" LOC = "V13" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 226 | NET "SF_A<22>" LOC = "V12" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 227 | NET "SF_A<23>" LOC = "N11" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 228 | NET "SF_A<24>" LOC = "A11" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 229 | NET "SF_BYTE" LOC = "C17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 230 | NET "SF_CE0" LOC = "D16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 231 | NET "SF_D<1>" LOC = "P10" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 232 | NET "SF_D<2>" LOC = "R10" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 233 | NET "SF_D<3>" LOC = "V9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 234 | NET "SF_D<4>" LOC = "U9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 235 | NET "SF_D<5>" LOC = "R9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 236 | NET "SF_D<6>" LOC = "M9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 237 | NET "SF_D<7>" LOC = "N9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 238 | NET "SF_D<8>" LOC = "R15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 239 | NET "SF_D<9>" LOC = "R16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 240 | NET "SF_D<10>" LOC = "P17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 241 | NET "SF_D<11>" LOC = "M15" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 242 | NET "SF_D<12>" LOC = "M16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 243 | NET "SF_D<13>" LOC = "P6" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 244 | NET "SF_D<14>" LOC = "R8" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 245 | NET "SF_D<15>" LOC = "T8" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 246 | NET "SF_OE" LOC = "C18" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 247 | NET "SF_STS" LOC = "B18" | IOSTANDARD = LVCMOS33 ; |
| 248 | NET "SF_WE" LOC = "D17" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 249 | # ==== STMicro SPI serial Flash (SPI) ==== |
| 250 | # some connections shared with SPI Flash, DAC, ADC, and AMP |
| 251 | NET "SPI_MISO" LOC = "N10" | IOSTANDARD = LVCMOS33 ; |
| 252 | #NET "SPI_MOSI" LOC = "T4" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 253 | #NET "SPI_SCK" LOC = "U16" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 254 | #NET "SPI_SS_B" LOC = "U3" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 255 | #NET "SPI_ALT_CS_JP11" LOC = "R12" | IOSTANDARD = LVCMOS33 | SLEW = SLOW | DRIVE = 6 ; |
| 256 | # ==== Slide Switches (SW) ==== |
| 257 | NET "SW<0>" LOC = "L13" | IOSTANDARD = LVTTL | PULLUP ; |
| 258 | NET "SW<1>" LOC = "L14" | IOSTANDARD = LVTTL | PULLUP ; |
| 259 | NET "SW<2>" LOC = "H18" | IOSTANDARD = LVTTL | PULLUP ; |
| 260 | NET "SW<3>" LOC = "N17" | IOSTANDARD = LVTTL | PULLUP ; |
| 261 | # ==== VGA Port (VGA) ==== |
| 262 | NET "VGA_BLUE" LOC = "G15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; |
| 263 | NET "VGA_GREEN" LOC = "H15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; |
| 264 | NET "VGA_HSYNC" LOC = "F15" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; |
| 265 | NET "VGA_RED" LOC = "H14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; |
| 266 | NET "VGA_VSYNC" LOC = "F14" | IOSTANDARD = LVTTL | DRIVE = 8 | SLEW = FAST ; |
| 267 | # ==== Xilinx CPLD (XC) ==== |
| 268 | #NET "XC_CMD<0>" LOC = "P18" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; |
| 269 | #NET "XC_CMD<1>" LOC = "N18" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; |
| 270 | #NET "XC_CPLD_EN" LOC = "B10" | IOSTANDARD = LVTTL ; |
| 271 | #NET "XC_D<0>" LOC = "G16" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; |
| 272 | #NET "XC_D<1>" LOC = "F18" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; |
| 273 | #NET "XC_D<2>" LOC = "F17" | IOSTANDARD = LVTTL | DRIVE = 4 | SLEW = SLOW ; |
| 274 | #NET "XC_TRIG" LOC = "R17" | IOSTANDARD = LVCMOS33 ; |
| 275 | #NET "XC_GCK0" LOC = "H16" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 276 | #NET "GCLK10" LOC = "C9" | IOSTANDARD = LVCMOS33 | DRIVE = 4 | SLEW = SLOW ; |
| 277 | NET "CLK_50MHZ" TNM_NET = "CLK_50MHZ"; |
| 278 | NET "clk_reg1" TNM_NET = "clk_reg1"; |
| 279 | TIMESPEC "TS_clk_reg1" = PERIOD "clk_reg1" 40 ns HIGH 50 %; |
plasma/logic/ram_image.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: Random Access Memory for Xilinx |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 11/06/05 |
| 5 | -- FILENAME: ram_xilinx.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Implements the RAM for Spartan 3 Xilinx FPGA |
| 11 | -- |
| 12 | -- Compile the MIPS C and assembly code into "test.axf". |
| 13 | -- Run convert.exe to change "test.axf" to "code.txt" which |
| 14 | -- will contain the hex values of the opcodes. |
| 15 | -- Next run "ram_image ram_xilinx.vhd code.txt ram_image.vhd", |
| 16 | -- to create the "ram_image.vhd" file that will have the opcodes |
| 17 | -- correctly placed inside the INIT_00 => strings. |
| 18 | -- Then include ram_image.vhd in the simulation/synthesis. |
| 19 | --------------------------------------------------------------------- |
| 20 | library ieee; |
| 21 | use ieee.std_logic_1164.all; |
| 22 | use ieee.std_logic_misc.all; |
| 23 | use ieee.std_logic_arith.all; |
| 24 | use ieee.std_logic_unsigned.all; |
| 25 | use work.mlite_pack.all; |
| 26 | library UNISIM; |
| 27 | use UNISIM.vcomponents.all; |
| 28 | |
| 29 | entity ram is |
| 30 | generic(memory_type : string := "DEFAULT"); |
| 31 | port(clk : in std_logic; |
| 32 | enable : in std_logic; |
| 33 | write_byte_enable : in std_logic_vector(3 downto 0); |
| 34 | address : in std_logic_vector(31 downto 2); |
| 35 | data_write : in std_logic_vector(31 downto 0); |
| 36 | data_read : out std_logic_vector(31 downto 0)); |
| 37 | end; --entity ram |
| 38 | |
| 39 | architecture logic of ram is |
| 40 | begin |
| 41 | |
| 42 | RAMB16_S9_inst0 : RAMB16_S9 |
| 43 | generic map ( |
| 44 | INIT_00 => X"afafafafafafafafafafafafafafafaf2308000c241400ac273c243c243c273c", |
| 45 | INIT_01 => X"8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f230c008c8c3caf00af00af2340afaf", |
| 46 | INIT_02 => X"acacacac0003373cac038cac8cac8cac8c243c40034040033423038f038f8f8f", |
| 47 | INIT_03 => X"000300ac0300000034038c8c8c8c8c8c8c8c8c8c8c8c3403acacacacacacacac", |
| 48 | INIT_04 => X"1c24001030008c24ac24ac9424003c00180003241c24a4248c0018ac2400003c", |
| 49 | INIT_05 => X"a00024241028302400a03c24243c3c0003001030008cacac242400003c000300", |
| 50 | INIT_06 => X"100010000c00102a0200260c24af08af2424240000afafafafaf270103001424", |
| 51 | INIT_07 => X"240c001a001427038f8f8f8f8f8f8f02240c240c000824102c24142c24142e24", |
| 52 | INIT_08 => X"3c240c3c240c3c240c3c240c3caf0cafafafafafafafafaf270008260c24240c", |
| 53 | INIT_09 => X"3c3c3c3c3c3c003c3c0c003c240c3c3c1430248c3c1030008c34ac3c3c24240c", |
| 54 | INIT_0A => X"0c3c240c3c270c260c260c260c260c240c3c240c3c240c3c240c3c240c3c240c", |
| 55 | INIT_0B => X"3c3c08240c3c000c000c8e0000008c0024003c3c102c260000142c2400000c24", |
| 56 | INIT_0C => X"3c3c080002a208000c000c00000c240c3c0008923c08ae000c000c00000c240c", |
| 57 | INIT_0D => X"080216a002260c00000010000c240c3c3c080216260c900200000010000c240c", |
| 58 | INIT_0E => X"0010000c240c3c3c08240c000c000c0014002490020000000010000c240c3c3c", |
| 59 | INIT_0F => X"240c3c021402240c000c260c8c021032021002240c000c260c8c02240c3c0000", |
| 60 | INIT_10 => X"14343c000c240c3c3c0800003c0016260c262610000c3c120008a23c243c3c08", |
| 61 | INIT_11 => X"0c000c2608240c3c000c020c240c3c00000c240c3c020c3c083c0c003c000c00", |
| 62 | INIT_12 => X"00100082260c00240800100080afafaf270003ac001030008c343c3c08240c00", |
| 63 | INIT_13 => X"2424142c3002242400afafafaf272703008f8f8f00140082000c2682000c2414", |
| 64 | INIT_14 => X"24243c3c2703008f8c3c10000caf2730038c343c240827038f8f8f8f0216260c", |
| 65 | INIT_15 => X"740a00616d20423a003531303241656c62747267650a24038c0014ac00248c3c", |
| 66 | INIT_16 => X"617965330a7769796532006f61796531006e706e724f303030206e6569612020", |
| 67 | INIT_17 => X"4600753900736838006979656137617965613673647475350a62697965340079", |
| 68 | INIT_18 => X"37336820660a0d786e6e0a786e750a3d6541206820720a3e00616f446f42316f", |
| 69 | INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 70 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 71 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 72 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 73 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 74 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 75 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 76 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 77 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 78 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 79 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 80 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 81 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 82 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 83 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 84 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 85 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 86 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 87 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 88 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 89 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 90 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 91 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 92 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 93 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 94 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 95 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 96 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 97 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 98 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 99 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 100 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 101 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 102 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 103 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 104 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 105 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 106 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 107 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 108 | port map ( |
| 109 | DO => data_read(31 downto 24), |
| 110 | DOP => open, |
| 111 | ADDR => address(12 downto 2), |
| 112 | CLK => clk, |
| 113 | DI => data_write(31 downto 24), |
| 114 | DIP => ZERO(0 downto 0), |
| 115 | EN => enable, |
| 116 | SSR => ZERO(0), |
| 117 | WE => write_byte_enable(3)); |
| 118 | |
| 119 | RAMB16_S9_inst1 : RAMB16_S9 |
| 120 | generic map ( |
| 121 | INIT_00 => X"b8afaeadacabaaa9a8a7a6a5a4a3a2a1bd000000a560a4a0bd1d8404a5059c1c", |
| 122 | INIT_01 => X"b9b8afaeadacabaaa9a8a7a6a5a4a3a2a1a50086c6c406bb00bb00ba5a1abfb9", |
| 123 | INIT_02 => X"9392919000405a1a06e0a606a606a606a6a50584e0029b401bbd60bb60bbbabf", |
| 124 | INIT_03 => X"00e000c4e0000085a2e09f9d9c9e979695949392919002e09f9d9c9e97969594", |
| 125 | INIT_04 => X"c0c60040420062636284658205620205c000e084c0a582c6a200c0a202a20502", |
| 126 | INIT_05 => X"c2e5070740a285634040036642020300e000404200828283020382040200e000", |
| 127 | INIT_06 => X"54405300000040220312310090b000bf1514130000b1b2b3b4b5bd00e004c3c6", |
| 128 | INIT_07 => X"040000208095bde0b0b1b2b3b4b5bf4004000400000090404282404282400250", |
| 129 | INIT_08 => X"04840004840004840004840004b000b1b2b3b4b5b6b7bebfbd12003100040400", |
| 130 | INIT_09 => X"021e171615144002060000048400041543420382146063004342830204038400", |
| 131 | INIT_0A => X"0002440002c400e400c400a40084004400024400024400024400024400024400", |
| 132 | INIT_0B => X"0202004400024000000044008000444383030402406203000040424240000044", |
| 133 | INIT_0C => X"0202000040500040004000400000440002000044020050400040004000004400", |
| 134 | INIT_0D => X"0000136251100000004040000044000202000011100044420000404000004400", |
| 135 | INIT_0E => X"404000004400020200040040000000a0a683a543420000004040000044000202", |
| 136 | INIT_0F => X"4400020060130400400030004450400200601304004000300044504400020000", |
| 137 | INIT_10 => X"4363030000440002020000400240535200101040000002110000501311120200", |
| 138 | INIT_11 => X"0000000300440002400040004400024000004400020000020006000004000000", |
| 139 | INIT_12 => X"00400002100040110080400082b1bfb0bd00e0a40040420062a3050200040040", |
| 140 | INIT_13 => X"646440624312111080bfb0b1b2bdbde000b0b1bf004000024000100200000451", |
| 141 | INIT_14 => X"63440302bde000bf6203400000bfbd42e06263030400bde0b0b1b2bf12111000", |
| 142 | INIT_15 => X"6957007320666f0a003a39313170726f6f686f73744742e0a200834045848205", |
| 143 | INIT_16 => X"64206d2e006f74206d2e007264206d2e007374752074303078616b206d726266", |
| 144 | INIT_17 => X"2e006d2e0075652e0074206d772e64206d772e73646f6d2e007974206d2e0074", |
| 145 | INIT_18 => X"3834207769430a3e2074433e206556207364006569654120007320526d203270", |
| 146 | INIT_19 => X"0004000080240080000000000000000000000000000000000000000000000000", |
| 147 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 148 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 149 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 150 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 151 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 152 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 153 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 154 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 155 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 156 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 157 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 158 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 159 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 160 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 161 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 162 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 163 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 164 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 165 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 166 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 167 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 168 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 169 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 170 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 171 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 172 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 173 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 174 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 175 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 176 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 177 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 178 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 179 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 180 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 181 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 182 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 183 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 184 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 185 | port map ( |
| 186 | DO => data_read(23 downto 16), |
| 187 | DOP => open, |
| 188 | ADDR => address(12 downto 2), |
| 189 | CLK => clk, |
| 190 | DI => data_write(23 downto 16), |
| 191 | DIP => ZERO(0 downto 0), |
| 192 | EN => enable, |
| 193 | SSR => ZERO(0), |
| 194 | WE => write_byte_enable(2)); |
| 195 | |
| 196 | RAMB16_S9_inst2 : RAMB16_S9 |
| 197 | generic map ( |
| 198 | INIT_00 => X"00000000000000000000000000000000ff00000100ff18000e000f000c008c00", |
| 199 | INIT_01 => X"000000000000000000000000000000000000022000002000d800d800ff700000", |
| 200 | INIT_02 => X"0000000000000010000000000000000000010060006060000000000000000000", |
| 201 | INIT_03 => X"0000000000201000000000000000000000000000000000000000000000000000", |
| 202 | INIT_04 => X"ffff00ff00000000000000000018301800000000ff0000ff0000000000282830", |
| 203 | INIT_05 => X"001000000000000c4000000d0d0000000000ff00000000000000202030000000", |
| 204 | INIT_06 => X"002000000200000090190002ff00000000000088900000000000ff100021ffff", |
| 205 | INIT_07 => X"0002000080ff00000000000000000010000200020000ff0000ffff00ffff00ff", |
| 206 | INIT_08 => X"000a02000c02000a02000a02000002000000000000000000ff9100ff02000002", |
| 207 | INIT_09 => X"000000000000f810000028100a02000000ff3c00000000000000002030000a02", |
| 208 | INIT_0A => X"02000b02000b020b020b020b020b020b02000b02000b02000b02000b02000a02", |
| 209 | INIT_0B => X"0000010b0200200200000000000000100c100000ff00ff90000000ff8000020c", |
| 210 | INIT_0C => X"00000100f80001200280002000000c0200000100000100200280002000000c02", |
| 211 | INIT_0D => X"0188ff00180002888098ff00000c0200000110ff00020010108088ff00000c02", |
| 212 | INIT_0E => X"980000000c0200000100022002000010ff20000010102028300000000c020000", |
| 213 | INIT_0F => X"0c020088ff180002200200000010ff0088001800022002000000100c02008880", |
| 214 | INIT_10 => X"ff561200000c0200000100f81080ff0002ff00ff000210008002001027100001", |
| 215 | INIT_11 => X"022000ff010b0200200220000c02009000000c02002002000100002810200000", |
| 216 | INIT_12 => X"00000000000220000280000000000000ff00000010ff00000000200001000220", |
| 217 | INIT_13 => X"000000000010ff009000000000ff00001000000000ff000020020000000200ff", |
| 218 | INIT_14 => X"0c0c0000000000000020ff000200ff0000000020000200000000000010ffff02", |
| 219 | INIT_15 => X"6e61006866726f0000343a30207220616f656d20697200000000ff0010000010", |
| 220 | INIT_16 => X"20726f20007265776f20006420726f20003a69204d680a303174656c6179696f", |
| 221 | INIT_17 => X"20007020006d63200065776f20200a726f20200a72207020007465776f200065", |
| 222 | INIT_18 => X"3e353169726f002068206f2068206100736400786e7364000068662020663879", |
| 223 | INIT_19 => X"0020000000202800000804040404040404040408040407070606060606050500", |
| 224 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 225 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 226 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 227 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 228 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 229 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 230 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 231 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 232 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 233 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 234 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 235 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 236 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 237 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 238 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 239 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 240 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 241 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 242 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 243 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 244 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 245 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 246 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 247 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 248 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 249 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 250 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 251 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 252 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 253 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 254 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 255 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 256 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 257 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 258 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 259 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 260 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 261 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 262 | port map ( |
| 263 | DO => data_read(15 downto 8), |
| 264 | DOP => open, |
| 265 | ADDR => address(12 downto 2), |
| 266 | CLK => clk, |
| 267 | DI => data_write(15 downto 8), |
| 268 | DIP => ZERO(0 downto 0), |
| 269 | EN => enable, |
| 270 | SSR => ZERO(0), |
| 271 | WE => write_byte_enable(1)); |
| 272 | |
| 273 | RAMB16_S9_inst3 : RAMB16_S9 |
| 274 | generic map ( |
| 275 | INIT_00 => X"4c4844403c3834302c2824201c181410980e000704fd2a00f8001000fc00f001", |
| 276 | INIT_01 => X"504c4844403c3834302c2824201c181410008a2410200060125c1058fc005450", |
| 277 | INIT_02 => X"0c08040000083c0048080c440840043c006000000800000801681360115c5854", |
| 278 | INIT_03 => X"00080c000810121900082c2824201c1814100c08040000082c2824201c181410", |
| 279 | INIT_04 => X"f4fe00fc80000004000200004021004011000802fb0400fe00000700ff214000", |
| 280 | INIT_05 => X"00213037020a0fff21080007000000000800fc8000000000d020214000000800", |
| 281 | INIT_06 => X"0c210e009100121021000145c910db28080d0a212114181c2024d0210802f7ff", |
| 282 | INIT_07 => X"0845000821d930081014181c202428210a450d4500d4a9111a9fed1abff10ad0", |
| 283 | INIT_08 => X"00d44f00344f00c84f00a84f00109c14181c2024282c3034c802d8ff45082045", |
| 284 | INIT_09 => X"000000000000090002802100e44f00000cff1c00001001000050000000ffe04f", |
| 285 | INIT_0A => X"4f00fc4f00f04fe04fc84fb44fa04f884f00704f00584f00404f00284f00f84f", |
| 286 | INIT_0B => X"0000406c4f00214f00b100000800002184800000d416cf2100c20ad021009120", |
| 287 | INIT_0C => X"0000400009003f214f21b12100c5444f00007600004000214f21b12100c5444f", |
| 288 | INIT_0D => X"4021fb002101912121218900c5544f00004021fb014500212121219a00c5544f", |
| 289 | INIT_0E => X"211e00c5544f0000400a45214f00b121fb21010021212121217600c5544f0000", |
| 290 | INIT_0F => X"644f0021f42b2045214f04b10021f00f210e2b2045214f04b10021644f002121", |
| 291 | INIT_10 => X"1f783400c5684f00004000090021f30191ff01fb008c000b210a001010000040", |
| 292 | INIT_11 => X"4f21b1cf6a6c4f00214f21b1384f002100c5244f0021450040028f210021a300", |
| 293 | INIT_12 => X"000d00000145210a6021160000141810e000080021fc020000200000400a4521", |
| 294 | INIT_13 => X"5730020a0f06fc1c211c101418e020082110141800f500002145010000450df8", |
| 295 | INIT_14 => X"fcdc0000180800100000fd008c10e80108002000494520081014181c06f8fc45", |
| 296 | INIT_15 => X"6769000a6c6f74000038300032200064742020666e6584080000fb0021040000", |
| 297 | INIT_16 => X"6265724d00642072724d000a7765724d000a6f4f656500303020646967206e72", |
| 298 | INIT_17 => X"43000a44000a6b43000a72726d520065726d52006561204a00652072724d000a", |
| 299 | INIT_18 => X"203632746d6e00006569750065696c002072003e20736400000a6c7444724b20", |
| 300 | INIT_19 => X"00001010200000207060fcfcfcfcfcfcfcfcfc08fcfc6404c07c6c3c30fcd400", |
| 301 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 302 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 303 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 304 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 305 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 306 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 307 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 308 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 309 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 310 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 311 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 312 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 313 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 314 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 315 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 316 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 317 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 318 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 319 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 320 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 321 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 322 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 323 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 324 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 325 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 326 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 327 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 328 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 329 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 330 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 331 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 332 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 333 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 334 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 335 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 336 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 337 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 338 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 339 | port map ( |
| 340 | DO => data_read(7 downto 0), |
| 341 | DOP => open, |
| 342 | ADDR => address(12 downto 2), |
| 343 | CLK => clk, |
| 344 | DI => data_write(7 downto 0), |
| 345 | DIP => ZERO(0 downto 0), |
| 346 | EN => enable, |
| 347 | SSR => ZERO(0), |
| 348 | WE => write_byte_enable(0)); |
| 349 | |
| 350 | end; --architecture logic |
plasma/logic/ram_xilinx.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: Random Access Memory for Xilinx |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 11/06/05 |
| 5 | -- FILENAME: ram_xilinx.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Implements the RAM for Spartan 3 Xilinx FPGA |
| 11 | -- |
| 12 | -- Compile the MIPS C and assembly code into "test.axf". |
| 13 | -- Run convert.exe to change "test.axf" to "code.txt" which |
| 14 | -- will contain the hex values of the opcodes. |
| 15 | -- Next run "ram_image ram_xilinx.vhd code.txt ram_image.vhd", |
| 16 | -- to create the "ram_image.vhd" file that will have the opcodes |
| 17 | -- correctly placed inside the INIT_00 => strings. |
| 18 | -- Then include ram_image.vhd in the simulation/synthesis. |
| 19 | --------------------------------------------------------------------- |
| 20 | library ieee; |
| 21 | use ieee.std_logic_1164.all; |
| 22 | use ieee.std_logic_misc.all; |
| 23 | use ieee.std_logic_arith.all; |
| 24 | use ieee.std_logic_unsigned.all; |
| 25 | use work.mlite_pack.all; |
| 26 | library UNISIM; |
| 27 | use UNISIM.vcomponents.all; |
| 28 | |
| 29 | entity ram is |
| 30 | generic(memory_type : string := "DEFAULT"); |
| 31 | port(clk : in std_logic; |
| 32 | enable : in std_logic; |
| 33 | write_byte_enable : in std_logic_vector(3 downto 0); |
| 34 | address : in std_logic_vector(31 downto 2); |
| 35 | data_write : in std_logic_vector(31 downto 0); |
| 36 | data_read : out std_logic_vector(31 downto 0)); |
| 37 | end; --entity ram |
| 38 | |
| 39 | architecture logic of ram is |
| 40 | begin |
| 41 | |
| 42 | RAMB16_S9_inst0 : RAMB16_S9 |
| 43 | generic map ( |
| 44 | INIT_00 => X"000000000000000000000000000000000000000000000000000000000c080400", |
| 45 | INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 46 | INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 47 | INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 48 | INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 49 | INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 50 | INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 51 | INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 52 | INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 53 | INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 54 | INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 55 | INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 56 | INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 57 | INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 58 | INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 59 | INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 60 | INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 61 | INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 62 | INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 63 | INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 64 | INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 65 | INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 66 | INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 67 | INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 68 | INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 69 | INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 70 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 71 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 72 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 73 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 74 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 75 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 76 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 77 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 78 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 79 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 80 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 81 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 82 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 83 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 84 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 85 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 86 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 87 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 88 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 89 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 90 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 91 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 92 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 93 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 94 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 95 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 96 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 97 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 98 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 99 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 100 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 101 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 102 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 103 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 104 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 105 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 106 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 107 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 108 | port map ( |
| 109 | DO => data_read(31 downto 24), |
| 110 | DOP => open, |
| 111 | ADDR => address(12 downto 2), |
| 112 | CLK => clk, |
| 113 | DI => data_write(31 downto 24), |
| 114 | DIP => ZERO(0 downto 0), |
| 115 | EN => enable, |
| 116 | SSR => ZERO(0), |
| 117 | WE => write_byte_enable(3)); |
| 118 | |
| 119 | RAMB16_S9_inst1 : RAMB16_S9 |
| 120 | generic map ( |
| 121 | INIT_00 => X"000000000000000000000000000000000000000000000000000000000d090501", |
| 122 | INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 123 | INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 124 | INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 125 | INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 126 | INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 127 | INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 128 | INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 129 | INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 130 | INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 131 | INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 132 | INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 133 | INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 134 | INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 135 | INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 136 | INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 137 | INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 138 | INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 139 | INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 140 | INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 141 | INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 142 | INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 143 | INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 144 | INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 145 | INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 146 | INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 147 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 148 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 149 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 150 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 151 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 152 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 153 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 154 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 155 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 156 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 157 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 158 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 159 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 160 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 161 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 162 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 163 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 164 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 165 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 166 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 167 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 168 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 169 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 170 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 171 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 172 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 173 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 174 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 175 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 176 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 177 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 178 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 179 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 180 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 181 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 182 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 183 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 184 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 185 | port map ( |
| 186 | DO => data_read(23 downto 16), |
| 187 | DOP => open, |
| 188 | ADDR => address(12 downto 2), |
| 189 | CLK => clk, |
| 190 | DI => data_write(23 downto 16), |
| 191 | DIP => ZERO(0 downto 0), |
| 192 | EN => enable, |
| 193 | SSR => ZERO(0), |
| 194 | WE => write_byte_enable(2)); |
| 195 | |
| 196 | RAMB16_S9_inst2 : RAMB16_S9 |
| 197 | generic map ( |
| 198 | INIT_00 => X"000000000000000000000000000000000000000000000000000000000e0a0602", |
| 199 | INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 200 | INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 201 | INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 202 | INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 203 | INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 204 | INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 205 | INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 206 | INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 207 | INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 208 | INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 209 | INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 210 | INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 211 | INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 212 | INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 213 | INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 214 | INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 215 | INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 216 | INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 217 | INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 218 | INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 219 | INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 220 | INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 221 | INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 222 | INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 223 | INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 224 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 225 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 226 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 227 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 228 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 229 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 230 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 231 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 232 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 233 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 234 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 235 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 236 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 237 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 238 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 239 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 240 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 241 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 242 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 243 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 244 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 245 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 246 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 247 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 248 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 249 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 250 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 251 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 252 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 253 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 254 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 255 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 256 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 257 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 258 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 259 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 260 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 261 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 262 | port map ( |
| 263 | DO => data_read(15 downto 8), |
| 264 | DOP => open, |
| 265 | ADDR => address(12 downto 2), |
| 266 | CLK => clk, |
| 267 | DI => data_write(15 downto 8), |
| 268 | DIP => ZERO(0 downto 0), |
| 269 | EN => enable, |
| 270 | SSR => ZERO(0), |
| 271 | WE => write_byte_enable(1)); |
| 272 | |
| 273 | RAMB16_S9_inst3 : RAMB16_S9 |
| 274 | generic map ( |
| 275 | INIT_00 => X"000000000000000000000000000000000000000000000000000000000f0b0703", |
| 276 | INIT_01 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 277 | INIT_02 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 278 | INIT_03 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 279 | INIT_04 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 280 | INIT_05 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 281 | INIT_06 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 282 | INIT_07 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 283 | INIT_08 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 284 | INIT_09 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 285 | INIT_0A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 286 | INIT_0B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 287 | INIT_0C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 288 | INIT_0D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 289 | INIT_0E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 290 | INIT_0F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 291 | INIT_10 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 292 | INIT_11 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 293 | INIT_12 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 294 | INIT_13 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 295 | INIT_14 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 296 | INIT_15 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 297 | INIT_16 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 298 | INIT_17 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 299 | INIT_18 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 300 | INIT_19 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 301 | INIT_1A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 302 | INIT_1B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 303 | INIT_1C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 304 | INIT_1D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 305 | INIT_1E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 306 | INIT_1F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 307 | INIT_20 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 308 | INIT_21 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 309 | INIT_22 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 310 | INIT_23 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 311 | INIT_24 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 312 | INIT_25 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 313 | INIT_26 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 314 | INIT_27 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 315 | INIT_28 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 316 | INIT_29 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 317 | INIT_2A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 318 | INIT_2B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 319 | INIT_2C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 320 | INIT_2D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 321 | INIT_2E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 322 | INIT_2F => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 323 | INIT_30 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 324 | INIT_31 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 325 | INIT_32 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 326 | INIT_33 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 327 | INIT_34 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 328 | INIT_35 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 329 | INIT_36 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 330 | INIT_37 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 331 | INIT_38 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 332 | INIT_39 => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 333 | INIT_3A => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 334 | INIT_3B => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 335 | INIT_3C => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 336 | INIT_3D => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 337 | INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", |
| 338 | INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000") |
| 339 | port map ( |
| 340 | DO => data_read(7 downto 0), |
| 341 | DOP => open, |
| 342 | ADDR => address(12 downto 2), |
| 343 | CLK => clk, |
| 344 | DI => data_write(7 downto 0), |
| 345 | DIP => ZERO(0 downto 0), |
| 346 | EN => enable, |
| 347 | SSR => ZERO(0), |
| 348 | WE => write_byte_enable(0)); |
| 349 | |
| 350 | end; --architecture logic |
plasma/logic/reg_bank.vhd |
| 1 | --------------------------------------------------------------------- |
| 2 | -- TITLE: Register Bank |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 2/2/01 |
| 5 | -- FILENAME: reg_bank.vhd |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Implements a register bank with 32 registers that are 32-bits wide. |
| 11 | -- There are two read-ports and one write port. |
| 12 | --------------------------------------------------------------------- |
| 13 | library ieee; |
| 14 | use ieee.std_logic_1164.all; |
| 15 | use ieee.std_logic_unsigned.all; |
| 16 | use work.mlite_pack.all; |
| 17 | --library UNISIM; --May need to uncomment for ModelSim |
| 18 | --use UNISIM.vcomponents.all; --May need to uncomment for ModelSim |
| 19 | |
| 20 | entity reg_bank is |
| 21 | generic(memory_type : string := "XILINX_16X"); |
| 22 | port(clk : in std_logic; |
| 23 | reset_in : in std_logic; |
| 24 | pause : in std_logic; |
| 25 | rs_index : in std_logic_vector(5 downto 0); |
| 26 | rt_index : in std_logic_vector(5 downto 0); |
| 27 | rd_index : in std_logic_vector(5 downto 0); |
| 28 | reg_source_out : out std_logic_vector(31 downto 0); |
| 29 | reg_target_out : out std_logic_vector(31 downto 0); |
| 30 | reg_dest_new : in std_logic_vector(31 downto 0); |
| 31 | intr_enable : out std_logic); |
| 32 | end; --entity reg_bank |
| 33 | |
| 34 | |
| 35 | -------------------------------------------------------------------- |
| 36 | -- The ram_block architecture attempts to use TWO dual-port memories. |
| 37 | -- Different FPGAs and ASICs need different implementations. |
| 38 | -- Choose one of the RAM implementations below. |
| 39 | -- I need feedback on this section! |
| 40 | -------------------------------------------------------------------- |
| 41 | architecture ram_block of reg_bank is |
| 42 | signal intr_enable_reg : std_logic; |
| 43 | type ram_type is array(31 downto 0) of std_logic_vector(31 downto 0); |
| 44 | |
| 45 | --controls access to dual-port memories |
| 46 | signal addr_read1, addr_read2 : std_logic_vector(4 downto 0); |
| 47 | signal addr_write : std_logic_vector(4 downto 0); |
| 48 | signal data_out1, data_out2 : std_logic_vector(31 downto 0); |
| 49 | signal write_enable : std_logic; |
| 50 | |
| 51 | begin |
| 52 | |
| 53 | reg_proc: process(clk, rs_index, rt_index, rd_index, reg_dest_new, |
| 54 | intr_enable_reg, data_out1, data_out2, reset_in, pause) |
| 55 | begin |
| 56 | --setup for first dual-port memory |
| 57 | if rs_index = "101110" then --reg_epc CP0 14 |
| 58 | addr_read1 <= "00000"; |
| 59 | else |
| 60 | addr_read1 <= rs_index(4 downto 0); |
| 61 | end if; |
| 62 | case rs_index is |
| 63 | when "000000" => reg_source_out <= ZERO; |
| 64 | when "101100" => reg_source_out <= ZERO(31 downto 1) & intr_enable_reg; |
| 65 | --interrupt vector address = 0x3c |
| 66 | when "111111" => reg_source_out <= ZERO(31 downto 8) & "00111100"; |
| 67 | when others => reg_source_out <= data_out1; |
| 68 | end case; |
| 69 | |
| 70 | --setup for second dual-port memory |
| 71 | addr_read2 <= rt_index(4 downto 0); |
| 72 | case rt_index is |
| 73 | when "000000" => reg_target_out <= ZERO; |
| 74 | when others => reg_target_out <= data_out2; |
| 75 | end case; |
| 76 | |
| 77 | --setup write port for both dual-port memories |
| 78 | if rd_index /= "000000" and rd_index /= "101100" and pause = '0' then |
| 79 | write_enable <= '1'; |
| 80 | else |
| 81 | write_enable <= '0'; |
| 82 | end if; |
| 83 | if rd_index = "101110" then --reg_epc CP0 14 |
| 84 | addr_write <= "00000"; |
| 85 | else |
| 86 | addr_write <= rd_index(4 downto 0); |
| 87 | end if; |
| 88 | |
| 89 | if reset_in = '1' then |
| 90 | intr_enable_reg <= '0'; |
| 91 | elsif rising_edge(clk) then |
| 92 | if rd_index = "101110" then --reg_epc CP0 14 |
| 93 | intr_enable_reg <= '0'; --disable interrupts |
| 94 | elsif rd_index = "101100" then |
| 95 | intr_enable_reg <= reg_dest_new(0); |
| 96 | end if; |
| 97 | end if; |
| 98 | |
| 99 | intr_enable <= intr_enable_reg; |
| 100 | end process; |
| 101 | |
| 102 | |
| 103 | -------------------------------------------------------------- |
| 104 | ---- Pick only ONE of the dual-port RAM implementations below! |
| 105 | -------------------------------------------------------------- |
| 106 | |
| 107 | -- Option #1 |
| 108 | -- One tri-port RAM, two read-ports, one write-port |
| 109 | -- 32 registers 32-bits wide |
| 110 | tri_port_mem: |
| 111 | if memory_type = "TRI_PORT_X" generate |
| 112 | ram_proc: process(clk, addr_read1, addr_read2, |
| 113 | addr_write, reg_dest_new, write_enable) |
| 114 | variable tri_port_ram : ram_type := (others => ZERO); |
| 115 | begin |
| 116 | data_out1 <= tri_port_ram(conv_integer(addr_read1)); |
| 117 | data_out2 <= tri_port_ram(conv_integer(addr_read2)); |
| 118 | if rising_edge(clk) then |
| 119 | if write_enable = '1' then |
| 120 | tri_port_ram(conv_integer(addr_write)) := reg_dest_new; |
| 121 | end if; |
| 122 | end if; |
| 123 | end process; |
| 124 | end generate; --tri_port_mem |
| 125 | |
| 126 | |
| 127 | -- Option #2 |
| 128 | -- Two dual-port RAMs, each with one read-port and one write-port |
| 129 | dual_port_mem: |
| 130 | if memory_type = "DUAL_PORT_" generate |
| 131 | ram_proc2: process(clk, addr_read1, addr_read2, |
| 132 | addr_write, reg_dest_new, write_enable) |
| 133 | variable dual_port_ram1 : ram_type := (others => ZERO); |
| 134 | variable dual_port_ram2 : ram_type := (others => ZERO); |
| 135 | begin |
| 136 | data_out1 <= dual_port_ram1(conv_integer(addr_read1)); |
| 137 | data_out2 <= dual_port_ram2(conv_integer(addr_read2)); |
| 138 | if rising_edge(clk) then |
| 139 | if write_enable = '1' then |
| 140 | dual_port_ram1(conv_integer(addr_write)) := reg_dest_new; |
| 141 | dual_port_ram2(conv_integer(addr_write)) := reg_dest_new; |
| 142 | end if; |
| 143 | end if; |
| 144 | end process; |
| 145 | end generate; --dual_port_mem |
| 146 | |
| 147 | |
| 148 | -- Option #3 |
| 149 | -- RAM16X1D: 16 x 1 positive edge write, asynchronous read dual-port |
| 150 | -- distributed RAM for all Xilinx FPGAs |
| 151 | -- From library UNISIM; use UNISIM.vcomponents.all; |
| 152 | xilinx_16x1d: |
| 153 | if memory_type = "XILINX_16X" generate |
| 154 | signal data_out1A, data_out1B : std_logic_vector(31 downto 0); |
| 155 | signal data_out2A, data_out2B : std_logic_vector(31 downto 0); |
| 156 | signal weA, weB : std_logic; |
| 157 | signal no_connect : std_logic_vector(127 downto 0); |
| 158 | begin |
| 159 | weA <= write_enable and not addr_write(4); --lower 16 registers |
| 160 | weB <= write_enable and addr_write(4); --upper 16 registers |
| 161 | |
| 162 | reg_loop: for i in 0 to 31 generate |
| 163 | begin |
| 164 | --Read port 1 lower 16 registers |
| 165 | reg_bit1a : RAM16X1D |
| 166 | port map ( |
| 167 | WCLK => clk, -- Port A write clock input |
| 168 | WE => weA, -- Port A write enable input |
| 169 | A0 => addr_write(0), -- Port A address[0] input bit |
| 170 | A1 => addr_write(1), -- Port A address[1] input bit |
| 171 | A2 => addr_write(2), -- Port A address[2] input bit |
| 172 | A3 => addr_write(3), -- Port A address[3] input bit |
| 173 | D => reg_dest_new(i), -- Port A 1-bit data input |
| 174 | DPRA0 => addr_read1(0), -- Port B address[0] input bit |
| 175 | DPRA1 => addr_read1(1), -- Port B address[1] input bit |
| 176 | DPRA2 => addr_read1(2), -- Port B address[2] input bit |
| 177 | DPRA3 => addr_read1(3), -- Port B address[3] input bit |
| 178 | DPO => data_out1A(i), -- Port B 1-bit data output |
| 179 | SPO => no_connect(i) -- Port A 1-bit data output |
| 180 | ); |
| 181 | --Read port 1 upper 16 registers |
| 182 | reg_bit1b : RAM16X1D |
| 183 | port map ( |
| 184 | WCLK => clk, -- Port A write clock input |
| 185 | WE => weB, -- Port A write enable input |
| 186 | A0 => addr_write(0), -- Port A address[0] input bit |
| 187 | A1 => addr_write(1), -- Port A address[1] input bit |
| 188 | A2 => addr_write(2), -- Port A address[2] input bit |
| 189 | A3 => addr_write(3), -- Port A address[3] input bit |
| 190 | D => reg_dest_new(i), -- Port A 1-bit data input |
| 191 | DPRA0 => addr_read1(0), -- Port B address[0] input bit |
| 192 | DPRA1 => addr_read1(1), -- Port B address[1] input bit |
| 193 | DPRA2 => addr_read1(2), -- Port B address[2] input bit |
| 194 | DPRA3 => addr_read1(3), -- Port B address[3] input bit |
| 195 | DPO => data_out1B(i), -- Port B 1-bit data output |
| 196 | SPO => no_connect(32+i) -- Port A 1-bit data output |
| 197 | ); |
| 198 | --Read port 2 lower 16 registers |
| 199 | reg_bit2a : RAM16X1D |
| 200 | port map ( |
| 201 | WCLK => clk, -- Port A write clock input |
| 202 | WE => weA, -- Port A write enable input |
| 203 | A0 => addr_write(0), -- Port A address[0] input bit |
| 204 | A1 => addr_write(1), -- Port A address[1] input bit |
| 205 | A2 => addr_write(2), -- Port A address[2] input bit |
| 206 | A3 => addr_write(3), -- Port A address[3] input bit |
| 207 | D => reg_dest_new(i), -- Port A 1-bit data input |
| 208 | DPRA0 => addr_read2(0), -- Port B address[0] input bit |
| 209 | DPRA1 => addr_read2(1), -- Port B address[1] input bit |
| 210 | DPRA2 => addr_read2(2), -- Port B address[2] input bit |
| 211 | DPRA3 => addr_read2(3), -- Port B address[3] input bit |
| 212 | DPO => data_out2A(i), -- Port B 1-bit data output |
| 213 | SPO => no_connect(64+i) -- Port A 1-bit data output |
| 214 | ); |
| 215 | --Read port 2 upper 16 registers |
| 216 | reg_bit2b : RAM16X1D |
| 217 | port map ( |
| 218 | WCLK => clk, -- Port A write clock input |
| 219 | WE => weB, -- Port A write enable input |
| 220 | A0 => addr_write(0), -- Port A address[0] input bit |
| 221 | A1 => addr_write(1), -- Port A address[1] input bit |
| 222 | A2 => addr_write(2), -- Port A address[2] input bit |
| 223 | A3 => addr_write(3), -- Port A address[3] input bit |
| 224 | D => reg_dest_new(i), -- Port A 1-bit data input |
| 225 | DPRA0 => addr_read2(0), -- Port B address[0] input bit |
| 226 | DPRA1 => addr_read2(1), -- Port B address[1] input bit |
| 227 | DPRA2 => addr_read2(2), -- Port B address[2] input bit |
| 228 | DPRA3 => addr_read2(3), -- Port B address[3] input bit |
| 229 | DPO => data_out2B(i), -- Port B 1-bit data output |
| 230 | SPO => no_connect(96+i) -- Port A 1-bit data output |
| 231 | ); |
| 232 | end generate; --reg_loop |
| 233 | |
| 234 | data_out1 <= data_out1A when addr_read1(4)='0' else data_out1B; |
| 235 | data_out2 <= data_out2A when addr_read2(4)='0' else data_out2B; |
| 236 | end generate; --xilinx_16x1d |
| 237 | |
| 238 | |
| 239 | -- Option #4 |
| 240 | -- Altera LPM_RAM_DP |
| 241 | altera_mem: |
| 242 | if memory_type = "ALTERA_LPM" generate |
| 243 | signal clk_delayed : std_logic; |
| 244 | signal addr_reg : std_logic_vector(4 downto 0); |
| 245 | signal data_reg : std_logic_vector(31 downto 0); |
| 246 | signal q1 : std_logic_vector(31 downto 0); |
| 247 | signal q2 : std_logic_vector(31 downto 0); |
| 248 | begin |
| 249 | -- Altera dual port RAMs must have the addresses registered (sampled |
| 250 | -- at the rising edge). This is very unfortunate. |
| 251 | -- Therefore, the dual port RAM read clock must delayed so that |
| 252 | -- the read address signal can be sent from the mem_ctrl block. |
| 253 | -- This solution also delays the how fast the registers are read so the |
| 254 | -- maximum clock speed is cut in half (12.5 MHz instead of 25 MHz). |
| 255 | |
| 256 | clk_delayed <= not clk; --Could be delayed by 1/4 clock cycle instead |
| 257 | dpram_bypass: process(clk, addr_write, reg_dest_new) |
| 258 | begin |
| 259 | if rising_edge(clk) and write_enable = '1' then |
| 260 | addr_reg <= addr_write; |
| 261 | data_reg <= reg_dest_new; |
| 262 | end if; |
| 263 | end process; --dpram_bypass |
| 264 | |
| 265 | -- Bypass dpram if reading what was just written (Altera limitation) |
| 266 | data_out1 <= q1 when addr_read1 /= addr_reg else data_reg; |
| 267 | data_out2 <= q2 when addr_read2 /= addr_reg else data_reg; |
| 268 | |
| 269 | lpm_ram_dp_component1 : lpm_ram_dp |
| 270 | generic map ( |
| 271 | LPM_WIDTH => 32, |
| 272 | LPM_WIDTHAD => 5, |
| 273 | --LPM_NUMWORDS => 0, |
| 274 | LPM_INDATA => "REGISTERED", |
| 275 | LPM_OUTDATA => "UNREGISTERED", |
| 276 | LPM_RDADDRESS_CONTROL => "REGISTERED", |
| 277 | LPM_WRADDRESS_CONTROL => "REGISTERED", |
| 278 | LPM_FILE => "UNUSED", |
| 279 | LPM_TYPE => "LPM_RAM_DP", |
| 280 | USE_EAB => "ON", |
| 281 | INTENDED_DEVICE_FAMILY => "UNUSED", |
| 282 | RDEN_USED => "FALSE", |
| 283 | LPM_HINT => "UNUSED") |
| 284 | port map ( |
| 285 | RDCLOCK => clk_delayed, |
| 286 | RDCLKEN => '1', |
| 287 | RDADDRESS => addr_read1, |
| 288 | RDEN => '1', |
| 289 | DATA => reg_dest_new, |
| 290 | WRADDRESS => addr_write, |
| 291 | WREN => write_enable, |
| 292 | WRCLOCK => clk, |
| 293 | WRCLKEN => '1', |
| 294 | Q => q1); |
| 295 | lpm_ram_dp_component2 : lpm_ram_dp |
| 296 | generic map ( |
| 297 | LPM_WIDTH => 32, |
| 298 | LPM_WIDTHAD => 5, |
| 299 | --LPM_NUMWORDS => 0, |
| 300 | LPM_INDATA => "REGISTERED", |
| 301 | LPM_OUTDATA => "UNREGISTERED", |
| 302 | LPM_RDADDRESS_CONTROL => "REGISTERED", |
| 303 | LPM_WRADDRESS_CONTROL => "REGISTERED", |
| 304 | LPM_FILE => "UNUSED", |
| 305 | LPM_TYPE => "LPM_RAM_DP", |
| 306 | USE_EAB => "ON", |
| 307 | INTENDED_DEVICE_FAMILY => "UNUSED", |
| 308 | RDEN_USED => "FALSE", |
| 309 | LPM_HINT => "UNUSED") |
| 310 | port map ( |
| 311 | RDCLOCK => clk_delayed, |
| 312 | RDCLKEN => '1', |
| 313 | RDADDRESS => addr_read2, |
| 314 | RDEN => '1', |
| 315 | DATA => reg_dest_new, |
| 316 | WRADDRESS => addr_write, |
| 317 | WREN => write_enable, |
| 318 | WRCLOCK => clk, |
| 319 | WRCLKEN => '1', |
| 320 | Q => q2); |
| 321 | end generate; --altera_mem |
| 322 | |
| 323 | end; --architecture ram_block |
plasma/logic/simulation/transcript |
| 1 | # // ModelSim SE 6.0d Apr 25 2005 Linux 2.6.32-21-generic |
| 2 | # // |
| 3 | # // Copyright Mentor Graphics Corporation 2005 |
| 4 | # // All Rights Reserved. |
| 5 | # // |
| 6 | # // THIS WORK CONTAINS TRADE SECRET AND |
| 7 | # // PROPRIETARY INFORMATION WHICH IS THE PROPERTY |
| 8 | # // OF MENTOR GRAPHICS CORPORATION OR ITS LICENSORS |
| 9 | # // AND IS SUBJECT TO LICENSE TERMS. |
| 10 | # // |
| 11 | # do plasma_3e_TB.do |
| 12 | # Reading /home/opt/cad/modeltech/linux/../modelsim.ini |
| 13 | # "work" maps to directory work. (Default mapping) |
| 14 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 15 | # -- Loading package standard |
| 16 | # -- Loading package std_logic_1164 |
| 17 | # -- Compiling package mlite_pack |
| 18 | # -- Compiling package body mlite_pack |
| 19 | # -- Loading package mlite_pack |
| 20 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 21 | # -- Loading package standard |
| 22 | # -- Loading package std_logic_1164 |
| 23 | # -- Loading package mlite_pack |
| 24 | # -- Compiling entity plasma |
| 25 | # -- Compiling architecture logic of plasma |
| 26 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 27 | # -- Loading package standard |
| 28 | # -- Loading package std_logic_1164 |
| 29 | # -- Loading package mlite_pack |
| 30 | # -- Compiling entity alu |
| 31 | # -- Compiling architecture logic of alu |
| 32 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 33 | # -- Loading package standard |
| 34 | # -- Loading package std_logic_1164 |
| 35 | # -- Loading package mlite_pack |
| 36 | # -- Compiling entity control |
| 37 | # -- Compiling architecture logic of control |
| 38 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 39 | # -- Loading package standard |
| 40 | # -- Loading package std_logic_1164 |
| 41 | # -- Loading package mlite_pack |
| 42 | # -- Compiling entity mem_ctrl |
| 43 | # -- Compiling architecture logic of mem_ctrl |
| 44 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 45 | # -- Loading package standard |
| 46 | # -- Loading package std_logic_1164 |
| 47 | # -- Loading package std_logic_arith |
| 48 | # -- Loading package std_logic_unsigned |
| 49 | # -- Loading package mlite_pack |
| 50 | # -- Compiling entity mult |
| 51 | # -- Compiling architecture logic of mult |
| 52 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 53 | # -- Loading package standard |
| 54 | # -- Loading package std_logic_1164 |
| 55 | # -- Loading package mlite_pack |
| 56 | # -- Compiling entity shifter |
| 57 | # -- Compiling architecture logic of shifter |
| 58 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 59 | # -- Loading package standard |
| 60 | # -- Loading package std_logic_1164 |
| 61 | # -- Loading package mlite_pack |
| 62 | # -- Compiling entity bus_mux |
| 63 | # -- Compiling architecture logic of bus_mux |
| 64 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 65 | # -- Loading package standard |
| 66 | # -- Loading package std_logic_1164 |
| 67 | # -- Loading package std_logic_arith |
| 68 | # -- Loading package std_logic_unsigned |
| 69 | # -- Loading package mlite_pack |
| 70 | # -- Compiling entity ddr_ctrl |
| 71 | # -- Compiling architecture logic of ddr_ctrl |
| 72 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 73 | # -- Loading package standard |
| 74 | # -- Loading package std_logic_1164 |
| 75 | # -- Loading package mlite_pack |
| 76 | # -- Loading package std_logic_arith |
| 77 | # -- Loading package std_logic_unsigned |
| 78 | # -- Compiling entity mlite_cpu |
| 79 | # -- Compiling architecture logic of mlite_cpu |
| 80 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 81 | # -- Loading package standard |
| 82 | # -- Loading package std_logic_1164 |
| 83 | # -- Loading package mlite_pack |
| 84 | # -- Compiling entity pc_next |
| 85 | # -- Compiling architecture logic of pc_next |
| 86 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 87 | # -- Loading package standard |
| 88 | # -- Loading package std_logic_1164 |
| 89 | # -- Loading package std_logic_arith |
| 90 | # -- Loading package std_logic_unsigned |
| 91 | # -- Loading package vcomponents |
| 92 | # -- Loading package mlite_pack |
| 93 | # -- Compiling entity cache |
| 94 | # -- Compiling architecture logic of cache |
| 95 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 96 | # -- Loading package standard |
| 97 | # -- Loading package std_logic_1164 |
| 98 | # -- Loading package std_logic_arith |
| 99 | # -- Loading package std_logic_unsigned |
| 100 | # -- Loading package mlite_pack |
| 101 | # -- Compiling entity eth_dma |
| 102 | # -- Compiling architecture logic of eth_dma |
| 103 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 104 | # -- Loading package standard |
| 105 | # -- Loading package std_logic_1164 |
| 106 | # -- Loading package mlite_pack |
| 107 | # -- Compiling entity pipeline |
| 108 | # -- Compiling architecture logic of pipeline |
| 109 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 110 | # -- Loading package standard |
| 111 | # -- Loading package std_logic_1164 |
| 112 | # -- Loading package std_logic_arith |
| 113 | # -- Loading package std_logic_unsigned |
| 114 | # -- Loading package mlite_pack |
| 115 | # -- Compiling entity reg_bank |
| 116 | # -- Compiling architecture ram_block of reg_bank |
| 117 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 118 | # -- Loading package standard |
| 119 | # -- Loading package std_logic_1164 |
| 120 | # -- Loading package attributes |
| 121 | # -- Loading package std_logic_misc |
| 122 | # -- Loading package std_logic_arith |
| 123 | # -- Loading package textio |
| 124 | # -- Loading package std_logic_textio |
| 125 | # -- Loading package std_logic_unsigned |
| 126 | # -- Loading package mlite_pack |
| 127 | # -- Compiling entity uart |
| 128 | # -- Compiling architecture logic of uart |
| 129 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 130 | # -- Loading package standard |
| 131 | # -- Loading package std_logic_1164 |
| 132 | # -- Loading package std_logic_arith |
| 133 | # -- Loading package std_logic_unsigned |
| 134 | # -- Compiling entity plasma_3e |
| 135 | # -- Compiling architecture logic of plasma_3e |
| 136 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 137 | # -- Loading package standard |
| 138 | # -- Loading package std_logic_1164 |
| 139 | # -- Loading package attributes |
| 140 | # -- Loading package std_logic_misc |
| 141 | # -- Loading package std_logic_arith |
| 142 | # -- Loading package std_logic_unsigned |
| 143 | # -- Loading package mlite_pack |
| 144 | # -- Loading package vcomponents |
| 145 | # -- Compiling entity ram |
| 146 | # -- Compiling architecture logic of ram |
| 147 | # Model Technology ModelSim SE vcom 6.0d Compiler 2005.04 Apr 25 2005 |
| 148 | # -- Loading package standard |
| 149 | # -- Loading package std_logic_1164 |
| 150 | # -- Loading package mlite_pack |
| 151 | # -- Loading package std_logic_arith |
| 152 | # -- Loading package std_logic_unsigned |
| 153 | # -- Compiling entity tbench |
| 154 | # -- Compiling architecture logic of tbench |
| 155 | # vsim -t 1ps tbench |
| 156 | # Loading /home/opt/cad/modeltech/linux/../std.standard |
| 157 | # Loading /home/opt/cad/modeltech/linux/../ieee.std_logic_1164(body) |
| 158 | # Loading work.mlite_pack(body) |
| 159 | # Loading /home/opt/cad/modeltech/linux/../ieee.std_logic_arith(body) |
| 160 | # Loading /home/opt/cad/modeltech/linux/../ieee.std_logic_unsigned(body) |
| 161 | # Loading work.tbench(logic) |
| 162 | # Loading work.plasma(logic) |
| 163 | # Loading work.mlite_cpu(logic) |
| 164 | # Loading work.pc_next(logic) |
| 165 | # Loading work.mem_ctrl(logic) |
| 166 | # Loading work.control(logic) |
| 167 | # Loading work.reg_bank(ram_block) |
| 168 | # Loading work.bus_mux(logic) |
| 169 | # Loading work.alu(logic) |
| 170 | # Loading work.shifter(logic) |
| 171 | # Loading work.mult(logic) |
| 172 | # Loading /opt/cad/modeltech/xilinx/vhdl/unisim.vcomponents |
| 173 | # Loading work.cache(logic) |
| 174 | # Loading /home/opt/cad/modeltech/linux/../synopsys.attributes |
| 175 | # Loading /home/opt/cad/modeltech/linux/../ieee.std_logic_misc(body) |
| 176 | # Loading work.ram(logic) |
| 177 | # Loading /home/opt/cad/modeltech/linux/../std.textio(body) |
| 178 | # Loading /home/opt/cad/modeltech/linux/../ieee.vital_timing(body) |
| 179 | # Loading /home/opt/cad/modeltech/linux/../ieee.vital_primitives(body) |
| 180 | # Loading /opt/cad/modeltech/xilinx/vhdl/unisim.vpkg(body) |
| 181 | # Loading /opt/cad/modeltech/xilinx/vhdl/unisim.ramb16_s9(ramb16_s9_v) |
| 182 | # Loading /home/opt/cad/modeltech/linux/../ieee.std_logic_textio(body) |
| 183 | # Loading work.uart(logic) |
| 184 | # Loading work.eth_dma(logic) |
| 185 | # .main_pane.mdi.interior.cs.vm.paneset.cli_0.wf.clip.cs |
| 186 | # .main_pane.workspace |
| 187 | # .main_pane.signals.interior.cs |
| 188 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 189 | # Time: 0 ps Iteration: 0 Instance: /tbench |
| 190 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 191 | # Time: 0 ps Iteration: 0 Instance: /tbench |
| 192 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 193 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/dma_gen2/u4_eth |
| 194 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 195 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/dma_gen2/u4_eth |
| 196 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 197 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u3_uart |
| 198 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 199 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/opt_cache2/u_cache |
| 200 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 201 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/opt_cache2/u_cache |
| 202 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 203 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/opt_cache2/u_cache |
| 204 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 205 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u8_mult |
| 206 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 207 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u8_mult |
| 208 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 209 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u8_mult |
| 210 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 211 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u8_mult |
| 212 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 213 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u8_mult |
| 214 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 215 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u8_mult |
| 216 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 217 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 218 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 219 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 220 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 221 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 222 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 223 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 224 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 225 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 226 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 227 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 228 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 229 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 230 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 231 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 232 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 233 | # Time: 0 ps Iteration: 0 Instance: /tbench/u1_plasma/u1_cpu |
| 234 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 235 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 236 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 237 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 238 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 239 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 240 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 241 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 242 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 243 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/opt_cache2/u_cache |
| 244 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 245 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 246 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 247 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 248 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 249 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 250 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 251 | # Time: 0 ps Iteration: 1 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 252 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 253 | # Time: 0 ps Iteration: 1 Instance: /tbench |
| 254 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 255 | # Time: 0 ps Iteration: 1 Instance: /tbench |
| 256 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 257 | # Time: 0 ps Iteration: 2 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank |
| 258 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 259 | # Time: 0 ps Iteration: 2 Instance: /tbench |
| 260 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 261 | # Time: 0 ps Iteration: 2 Instance: /tbench |
| 262 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 263 | # Time: 0 ps Iteration: 2 Instance: /tbench/u1_plasma/opt_cache2/u_cache |
| 264 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 265 | # Time: 0 ps Iteration: 3 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 266 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 267 | # Time: 0 ps Iteration: 3 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 268 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 269 | # Time: 0 ps Iteration: 3 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 270 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 271 | # Time: 0 ps Iteration: 3 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 272 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 273 | # Time: 0 ps Iteration: 3 Instance: /tbench/u1_plasma/opt_cache2/u_cache |
| 274 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 275 | # Time: 0 ps Iteration: 4 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 276 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 277 | # Time: 0 ps Iteration: 4 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 278 | # ** Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es). |
| 279 | # Time: 0 ps Iteration: 4 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 280 | # ** Warning: CONV_INTEGER: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, and it has been converted to 0. |
| 281 | # Time: 0 ps Iteration: 4 Instance: /tbench/u1_plasma/u1_cpu/u4_reg_bank/tri_port_mem |
| 282 | # Break key hit |
| 283 | # Simulation stop requested. |
plasma/tools/mlite.c |
| 1 | /*------------------------------------------------------------------- |
| 2 | -- TITLE: Plasma CPU in software. Executes MIPS(tm) opcodes. |
| 3 | -- AUTHOR: Steve Rhoads (rhoadss@yahoo.com) |
| 4 | -- DATE CREATED: 1/31/01 |
| 5 | -- FILENAME: mlite.c |
| 6 | -- PROJECT: Plasma CPU core |
| 7 | -- COPYRIGHT: Software placed into the public domain by the author. |
| 8 | -- Software 'as is' without warranty. Author liable for nothing. |
| 9 | -- DESCRIPTION: |
| 10 | -- Plasma CPU simulator in C code. |
| 11 | -- This file served as the starting point for the VHDL code. |
| 12 | -- Assumes running on a little endian PC. |
| 13 | --------------------------------------------------------------------*/ |
| 14 | #include <stdio.h> |
| 15 | #include <stdlib.h> |
| 16 | #include <string.h> |
| 17 | #include <ctype.h> |
| 18 | #include <assert.h> |
| 19 | |
| 20 | //#define ENABLE_CACHE |
| 21 | #define SIMPLE_CACHE |
| 22 | |
| 23 | #define MEM_SIZE (1024*1024*2) |
| 24 | #define ntohs(A) ( ((A)>>8) | (((A)&0xff)<<8) ) |
| 25 | #define htons(A) ntohs(A) |
| 26 | #define ntohl(A) ( ((A)>>24) | (((A)&0xff0000)>>8) | (((A)&0xff00)<<8) | ((A)<<24) ) |
| 27 | #define htonl(A) ntohl(A) |
| 28 | |
| 29 | #ifndef WIN32 |
| 30 | //Support for Linux |
| 31 | #define putch putchar |
| 32 | #include <termios.h> |
| 33 | #include <unistd.h> |
| 34 | |
| 35 | void Sleep(unsigned int value) |
| 36 | { |
| 37 | usleep(value * 1000); |
| 38 | } |
| 39 | |
| 40 | int kbhit(void) |
| 41 | { |
| 42 | struct termios oldt, newt; |
| 43 | struct timeval tv; |
| 44 | fd_set read_fd; |
| 45 | |
| 46 | tcgetattr(STDIN_FILENO, &oldt); |
| 47 | newt = oldt; |
| 48 | newt.c_lflag &= ~(ICANON | ECHO); |
| 49 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); |
| 50 | tv.tv_sec=0; |
| 51 | tv.tv_usec=0; |
| 52 | FD_ZERO(&read_fd); |
| 53 | FD_SET(0,&read_fd); |
| 54 | if(select(1, &read_fd, NULL, NULL, &tv) == -1) |
| 55 | return 0; |
| 56 | //tcsetattr(STDIN_FILENO, TCSANOW, &oldt); |
| 57 | if(FD_ISSET(0,&read_fd)) |
| 58 | return 1; |
| 59 | return 0; |
| 60 | } |
| 61 | |
| 62 | int getch(void) |
| 63 | { |
| 64 | struct termios oldt, newt; |
| 65 | int ch; |
| 66 | |
| 67 | tcgetattr(STDIN_FILENO, &oldt); |
| 68 | newt = oldt; |
| 69 | newt.c_lflag &= ~(ICANON | ECHO); |
| 70 | tcsetattr(STDIN_FILENO, TCSANOW, &newt); |
| 71 | ch = getchar(); |
| 72 | //tcsetattr(STDIN_FILENO, TCSANOW, &oldt); |
| 73 | return ch; |
| 74 | } |
| 75 | #else |
| 76 | //Support for Windows |
| 77 | #include <conio.h> |
| 78 | extern void __stdcall Sleep(unsigned long value); |
| 79 | #endif |
| 80 | |
| 81 | #define UART_WRITE 0x20000000 |
| 82 | #define UART_READ 0x20000000 |
| 83 | #define IRQ_MASK 0x20000010 |
| 84 | #define IRQ_STATUS 0x20000020 |
| 85 | #define CONFIG_REG 0x20000070 |
| 86 | #define MMU_PROCESS_ID 0x20000080 |
| 87 | #define MMU_FAULT_ADDR 0x20000090 |
| 88 | #define MMU_TLB 0x200000a0 |
| 89 | |
| 90 | #define IRQ_UART_READ_AVAILABLE 0x001 |
| 91 | #define IRQ_UART_WRITE_AVAILABLE 0x002 |
| 92 | #define IRQ_COUNTER18_NOT 0x004 |
| 93 | #define IRQ_COUNTER18 0x008 |
| 94 | #define IRQ_MMU 0x200 |
| 95 | |
| 96 | #define MMU_ENTRIES 4 |
| 97 | #define MMU_MASK (1024*4-1) |
| 98 | |
| 99 | typedef struct |
| 100 | { |
| 101 | unsigned int virtualAddress; |
| 102 | unsigned int physicalAddress; |
| 103 | } MmuEntry; |
| 104 | |
| 105 | typedef struct { |
| 106 | int r[32]; |
| 107 | int pc, pc_next, epc; |
| 108 | unsigned int hi; |
| 109 | unsigned int lo; |
| 110 | int status; |
| 111 | int userMode; |
| 112 | int processId; |
| 113 | int exceptionId; |
| 114 | int faultAddr; |
| 115 | int irqStatus; |
| 116 | int skip; |
| 117 | unsigned char *mem; |
| 118 | int wakeup; |
| 119 | int big_endian; |
| 120 | MmuEntry mmuEntry[MMU_ENTRIES]; |
| 121 | } State; |
| 122 | |
| 123 | static char *opcode_string[]={ |
| 124 | "SPECIAL","REGIMM","J","JAL","BEQ","BNE","BLEZ","BGTZ", |
| 125 | "ADDI","ADDIU","SLTI","SLTIU","ANDI","ORI","XORI","LUI", |
| 126 | "COP0","COP1","COP2","COP3","BEQL","BNEL","BLEZL","BGTZL", |
| 127 | "?","?","?","?","?","?","?","?", |
| 128 | "LB","LH","LWL","LW","LBU","LHU","LWR","?", |
| 129 | "SB","SH","SWL","SW","?","?","SWR","CACHE", |
| 130 | "LL","LWC1","LWC2","LWC3","?","LDC1","LDC2","LDC3" |
| 131 | "SC","SWC1","SWC2","SWC3","?","SDC1","SDC2","SDC3" |
| 132 | }; |
| 133 | |
| 134 | static char *special_string[]={ |
| 135 | "SLL","?","SRL","SRA","SLLV","?","SRLV","SRAV", |
| 136 | "JR","JALR","MOVZ","MOVN","SYSCALL","BREAK","?","SYNC", |
| 137 | "MFHI","MTHI","MFLO","MTLO","?","?","?","?", |
| 138 | "MULT","MULTU","DIV","DIVU","?","?","?","?", |
| 139 | "ADD","ADDU","SUB","SUBU","AND","OR","XOR","NOR", |
| 140 | "?","?","SLT","SLTU","?","DADDU","?","?", |
| 141 | "TGE","TGEU","TLT","TLTU","TEQ","?","TNE","?", |
| 142 | "?","?","?","?","?","?","?","?" |
| 143 | }; |
| 144 | |
| 145 | static char *regimm_string[]={ |
| 146 | "BLTZ","BGEZ","BLTZL","BGEZL","?","?","?","?", |
| 147 | "TGEI","TGEIU","TLTI","TLTIU","TEQI","?","TNEI","?", |
| 148 | "BLTZAL","BEQZAL","BLTZALL","BGEZALL","?","?","?","?", |
| 149 | "?","?","?","?","?","?","?","?" |
| 150 | }; |
| 151 | |
| 152 | static unsigned int HWMemory[8]; |
| 153 | |
| 154 | |
| 155 | static int mem_read(State *s, int size, unsigned int address) |
| 156 | { |
| 157 | unsigned int value=0, ptr; |
| 158 | |
| 159 | s->irqStatus |= IRQ_UART_WRITE_AVAILABLE; |
| 160 | switch(address) |
| 161 | { |
| 162 | case UART_READ: |
| 163 | if(kbhit()) |
| 164 | HWMemory[0] = getch(); |
| 165 | s->irqStatus &= ~IRQ_UART_READ_AVAILABLE; //clear bit |
| 166 | return HWMemory[0]; |
| 167 | case IRQ_MASK: |
| 168 | return HWMemory[1]; |
| 169 | case IRQ_MASK + 4: |
| 170 | Sleep(10); |
| 171 | return 0; |
| 172 | case IRQ_STATUS: |
| 173 | if(kbhit()) |
| 174 | s->irqStatus |= IRQ_UART_READ_AVAILABLE; |
| 175 | return s->irqStatus; |
| 176 | case MMU_PROCESS_ID: |
| 177 | return s->processId; |
| 178 | case MMU_FAULT_ADDR: |
| 179 | return s->faultAddr; |
| 180 | } |
| 181 | |
| 182 | ptr = (unsigned int)s->mem + (address % MEM_SIZE); |
| 183 | |
| 184 | if(0x10000000 <= address && address < 0x10000000 + 1024*1024) |
| 185 | ptr += 1024*1024; |
| 186 | |
| 187 | switch(size) |
| 188 | { |
| 189 | case 4: |
| 190 | if(address & 3) |
| 191 | printf("Unaligned access PC=0x%x address=0x%x\n", (int)s->pc, (int)address); |
| 192 | assert((address & 3) == 0); |
| 193 | value = *(int*)ptr; |
| 194 | if(s->big_endian) |
| 195 | value = ntohl(value); |
| 196 | break; |
| 197 | case 2: |
| 198 | assert((address & 1) == 0); |
| 199 | value = *(unsigned short*)ptr; |
| 200 | if(s->big_endian) |
| 201 | value = ntohs((unsigned short)value); |
| 202 | break; |
| 203 | case 1: |
| 204 | value = *(unsigned char*)ptr; |
| 205 | break; |
| 206 | default: |
| 207 | printf("ERROR"); |
| 208 | } |
| 209 | return(value); |
| 210 | } |
| 211 | |
| 212 | static void mem_write(State *s, int size, int unsigned address, unsigned int value) |
| 213 | { |
| 214 | unsigned int ptr; |
| 215 | |
| 216 | switch(address) |
| 217 | { |
| 218 | case UART_WRITE: |
| 219 | putch(value); |
| 220 | fflush(stdout); |
| 221 | return; |
| 222 | case IRQ_MASK: |
| 223 | HWMemory[1] = value; |
| 224 | return; |
| 225 | case IRQ_STATUS: |
| 226 | s->irqStatus = value; |
| 227 | return; |
| 228 | case CONFIG_REG: |
| 229 | return; |
| 230 | case MMU_PROCESS_ID: |
| 231 | //printf("processId=%d\n", value); |
| 232 | s->processId = value; |
| 233 | return; |
| 234 | } |
| 235 | |
| 236 | if(MMU_TLB <= address && address <= MMU_TLB+MMU_ENTRIES * 8) |
| 237 | { |
| 238 | //printf("TLB 0x%x 0x%x\n", address - MMU_TLB, value); |
| 239 | ptr = (unsigned int)s->mmuEntry + address - MMU_TLB; |
| 240 | *(int*)ptr = value; |
| 241 | s->irqStatus &= ~IRQ_MMU; |
| 242 | return; |
| 243 | } |
| 244 | |
| 245 | ptr = (unsigned int)s->mem + (address % MEM_SIZE); |
| 246 | |
| 247 | if(0x10000000 <= address && address < 0x10000000 + 1024*1024) |
| 248 | ptr += 1024*1024; |
| 249 | |
| 250 | switch(size) |
| 251 | { |
| 252 | case 4: |
| 253 | assert((address & 3) == 0); |
| 254 | if(s->big_endian) |
| 255 | value = htonl(value); |
| 256 | *(int*)ptr = value; |
| 257 | break; |
| 258 | case 2: |
| 259 | assert((address & 1) == 0); |
| 260 | if(s->big_endian) |
| 261 | value = htons((unsigned short)value); |
| 262 | *(short*)ptr = (unsigned short)value; |
| 263 | break; |
| 264 | case 1: |
| 265 | *(char*)ptr = (unsigned char)value; |
| 266 | break; |
| 267 | default: |
| 268 | printf("ERROR"); |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | #ifdef ENABLE_CACHE |
| 273 | /************* Optional MMU and cache implementation *************/ |
| 274 | /* TAG = VirtualAddress | ProcessId | WriteableBit */ |
| 275 | unsigned int mmu_lookup(State *s, unsigned int processId, |
| 276 | unsigned int address, int write) |
| 277 | { |
| 278 | int i; |
| 279 | unsigned int compare, tag; |
| 280 | |
| 281 | if(processId == 0 || s->userMode == 0) |
| 282 | return address; |
| 283 | //if(address < 0x30000000) |
| 284 | // return address; |
| 285 | compare = (address & ~MMU_MASK) | (processId << 1); |
| 286 | for(i = 0; i < MMU_ENTRIES; ++i) |
| 287 | { |
| 288 | tag = s->mmuEntry[i].virtualAddress; |
| 289 | if((tag & ~1) == compare && (write == 0 || (tag & 1))) |
| 290 | return s->mmuEntry[i].physicalAddress | (address & MMU_MASK); |
| 291 | } |
| 292 | //printf("\nMMUTlbMiss 0x%x PC=0x%x w=%d pid=%d user=%d\n", |
| 293 | // address, s->pc, write, processId, s->userMode); |
| 294 | //printf("m"); |
| 295 | s->exceptionId = 1; |
| 296 | s->faultAddr = address & ~MMU_MASK; |
| 297 | s->irqStatus |= IRQ_MMU; |
| 298 | return address; |
| 299 | } |
| 300 | |
| 301 | |
| 302 | #define CACHE_SET_ASSOC_LN2 0 |
| 303 | #define CACHE_SET_ASSOC (1 << CACHE_SET_ASSOC_LN2) |
| 304 | #define CACHE_SIZE_LN2 (13 - CACHE_SET_ASSOC_LN2) //8 KB |
| 305 | #define CACHE_SIZE (1 << CACHE_SIZE_LN2) |
| 306 | #define CACHE_LINE_SIZE_LN2 2 //4 bytes |
| 307 | #define CACHE_LINE_SIZE (1 << CACHE_LINE_SIZE_LN2) |
| 308 | |
| 309 | static int cacheData[CACHE_SET_ASSOC][CACHE_SIZE/sizeof(int)]; |
| 310 | static int cacheAddr[CACHE_SET_ASSOC][CACHE_SIZE/CACHE_LINE_SIZE]; |
| 311 | static int cacheSetNext; |
| 312 | static int cacheMiss, cacheWriteBack, cacheCount; |
| 313 | |
| 314 | static void cache_init(void) |
| 315 | { |
| 316 | int set, i; |
| 317 | for(set = 0; set < CACHE_SET_ASSOC; ++set) |
| 318 | { |
| 319 | for(i = 0; i < CACHE_SIZE/CACHE_LINE_SIZE; ++i) |
| 320 | cacheAddr[set][i] = 0xffff0000; |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | /* Write-back cache memory tagged by virtual address and processId */ |
| 325 | /* TAG = virtualAddress | processId | dirtyBit */ |
| 326 | static int cache_load(State *s, unsigned int address, int write) |
| 327 | { |
| 328 | int set, i, pid, miss, offsetAddr, offsetData, offsetMem; |
| 329 | unsigned int addrTagMatch, addrPrevMatch=0; |
| 330 | unsigned int addrPrev; |
| 331 | unsigned int addressPhysical, tag; |
| 332 | |
| 333 | ++cacheCount; |
| 334 | addrTagMatch = address & ~(CACHE_SIZE-1); |
| 335 | offsetAddr = (address & (CACHE_SIZE-1)) >> CACHE_LINE_SIZE_LN2; |
| 336 | |
| 337 | /* Find match */ |
| 338 | miss = 1; |
| 339 | for(set = 0; set < CACHE_SET_ASSOC; ++set) |
| 340 | { |
| 341 | addrPrevMatch = cacheAddr[set][offsetAddr] & ~(CACHE_SIZE-1); |
| 342 | if(addrPrevMatch == addrTagMatch) |
| 343 | { |
| 344 | miss = 0; |
| 345 | break; |
| 346 | } |
| 347 | } |
| 348 | |
| 349 | /* Cache miss? */ |
| 350 | if(miss) |
| 351 | { |
| 352 | ++cacheMiss; |
| 353 | set = cacheSetNext; |
| 354 | cacheSetNext = (cacheSetNext + 1) & (CACHE_SET_ASSOC-1); |
| 355 | } |
| 356 | //else if(write || (address >> 28) != 0x1) |
| 357 | //{ |
| 358 | // tag = cacheAddr[set][offsetAddr]; |
| 359 | // pid = (tag & (CACHE_SIZE-1)) >> 1; |
| 360 | // if(pid != s->processId) |
| 361 | // miss = 1; |
| 362 | //} |
| 363 | |
| 364 | if(miss) |
| 365 | { |
| 366 | offsetData = address & (CACHE_SIZE-1) & ~(CACHE_LINE_SIZE-1); |
| 367 | |
| 368 | /* Cache line dirty? */ |
| 369 | if(cacheAddr[set][offsetAddr] & 1) |
| 370 | { |
| 371 | /* Write back cache line */ |
| 372 | tag = cacheAddr[set][offsetAddr]; |
| 373 | addrPrev = tag & ~(CACHE_SIZE-1); |
| 374 | addrPrev |= address & (CACHE_SIZE-1); |
| 375 | pid = (tag & (CACHE_SIZE-1)) >> 1; |
| 376 | addressPhysical = mmu_lookup(s, pid, addrPrev, 1); //virtual->physical |
| 377 | if(s->exceptionId) |
| 378 | return 0; |
| 379 | offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1); |
| 380 | for(i = 0; i < CACHE_LINE_SIZE; i += 4) |
| 381 | mem_write(s, 4, offsetMem + i, cacheData[set][(offsetData + i) >> 2]); |
| 382 | ++cacheWriteBack; |
| 383 | } |
| 384 | |
| 385 | /* Read cache line */ |
| 386 | addressPhysical = mmu_lookup(s, s->processId, address, write); //virtual->physical |
| 387 | if(s->exceptionId) |
| 388 | return 0; |
| 389 | offsetMem = addressPhysical & ~(CACHE_LINE_SIZE-1); |
| 390 | cacheAddr[set][offsetAddr] = addrTagMatch; |
| 391 | for(i = 0; i < CACHE_LINE_SIZE; i += 4) |
| 392 | cacheData[set][(offsetData + i) >> 2] = mem_read(s, 4, offsetMem + i); |
| 393 | } |
| 394 | cacheAddr[set][offsetAddr] |= write; |
| 395 | return set; |
| 396 | } |
| 397 | |
| 398 | static int cache_read(State *s, int size, unsigned int address) |
| 399 | { |
| 400 | int set, offset; |
| 401 | int value; |
| 402 | |
| 403 | if((address & 0xfe000000) != 0x10000000) |
| 404 | return mem_read(s, size, address); |
| 405 | |
| 406 | set = cache_load(s, address, 0); |
| 407 | if(s->exceptionId) |
| 408 | return 0; |
| 409 | offset = (address & (CACHE_SIZE-1)) >> 2; |
| 410 | value = cacheData[set][offset]; |
| 411 | if(s->big_endian) |
| 412 | address ^= 3; |
| 413 | switch(size) |
| 414 | { |
| 415 | case 2: |
| 416 | value = (value >> ((address & 2) << 3)) & 0xffff; |
| 417 | break; |
| 418 | case 1: |
| 419 | value = (value >> ((address & 3) << 3)) & 0xff; |
| 420 | break; |
| 421 | } |
| 422 | return value; |
| 423 | } |
| 424 | |
| 425 | static void cache_write(State *s, int size, int unsigned address, unsigned int value) |
| 426 | { |
| 427 | int set, offset; |
| 428 | unsigned int mask; |
| 429 | |
| 430 | if((address >> 28) != 0x1) // && (s->processId == 0 || s->userMode == 0)) |
| 431 | { |
| 432 | mem_write(s, size, address, value); |
| 433 | return; |
| 434 | } |
| 435 | |
| 436 | set = cache_load(s, address, 1); |
| 437 | if(s->exceptionId) |
| 438 | return; |
| 439 | offset = (address & (CACHE_SIZE-1)) >> 2; |
| 440 | if(s->big_endian) |
| 441 | address ^= 3; |
| 442 | switch(size) |
| 443 | { |
| 444 | case 2: |
| 445 | value &= 0xffff; |
| 446 | value |= value << 16; |
| 447 | mask = 0xffff << ((address & 2) << 3); |
| 448 | break; |
| 449 | case 1: |
| 450 | value &= 0xff; |
| 451 | value |= (value << 8) | (value << 16) | (value << 24); |
| 452 | mask = 0xff << ((address & 3) << 3); |
| 453 | break; |
| 454 | case 4: |
| 455 | default: |
| 456 | mask = 0xffffffff; |
| 457 | break; |
| 458 | } |
| 459 | cacheData[set][offset] = (value & mask) | (cacheData[set][offset] & ~mask); |
| 460 | } |
| 461 | |
| 462 | #define mem_read cache_read |
| 463 | #define mem_write cache_write |
| 464 | |
| 465 | #else |
| 466 | static void cache_init(void) {} |
| 467 | #endif |
| 468 | |
| 469 | |
| 470 | #ifdef SIMPLE_CACHE |
| 471 | |
| 472 | //Write through direct mapped 4KB cache |
| 473 | #define CACHE_MISS 0x1ff |
| 474 | static unsigned int cacheData[1024]; |
| 475 | static unsigned int cacheAddr[1024]; //9-bit addresses |
| 476 | static int cacheTry, cacheMiss, cacheInit; |
| 477 | |
| 478 | static int cache_read(State *s, int size, unsigned int address) |
| 479 | { |
| 480 | int offset; |
| 481 | unsigned int value, value2, address2=address; |
| 482 | |
| 483 | if(cacheInit == 0) |
| 484 | { |
| 485 | cacheInit = 1; |
| 486 | for(offset = 0; offset < 1024; ++offset) |
| 487 | cacheAddr[offset] = CACHE_MISS; |
| 488 | } |
| 489 | |
| 490 | offset = address >> 20; |
| 491 | if(offset != 0x100 && offset != 0x101) |
| 492 | return mem_read(s, size, address); |
| 493 | |
| 494 | ++cacheTry; |
| 495 | offset = (address >> 2) & 0x3ff; |
| 496 | if(cacheAddr[offset] != (address >> 12) || cacheAddr[offset] == CACHE_MISS) |
| 497 | { |
| 498 | ++cacheMiss; |
| 499 | cacheAddr[offset] = address >> 12; |
| 500 | cacheData[offset] = mem_read(s, 4, address & ~3); |
| 501 | } |
| 502 | value = cacheData[offset]; |
| 503 | if(s->big_endian) |
| 504 | address ^= 3; |
| 505 | switch(size) |
| 506 | { |
| 507 | case 2: |
| 508 | value = (value >> ((address & 2) << 3)) & 0xffff; |
| 509 | break; |
| 510 | case 1: |
| 511 | value = (value >> ((address & 3) << 3)) & 0xff; |
| 512 | break; |
| 513 | } |
| 514 | |
| 515 | //Debug testing |
| 516 | value2 = mem_read(s, size, address2); |
| 517 | if(value != value2) |
| 518 | printf("miss match\n"); |
| 519 | //if((cacheTry & 0xffff) == 0) printf("\n***cache(%d,%d)\n ", cacheMiss, cacheTry); |
| 520 | return value; |
| 521 | } |
| 522 | |
| 523 | static void cache_write(State *s, int size, int unsigned address, unsigned int value) |
| 524 | { |
| 525 | int offset; |
| 526 | |
| 527 | mem_write(s, size, address, value); |
| 528 | |
| 529 | offset = address >> 20; |
| 530 | if(offset != 0x100 && offset != 0x101) |
| 531 | return; |
| 532 | |
| 533 | offset = (address >> 2) & 0x3ff; |
| 534 | if(size != 4) |
| 535 | { |
| 536 | cacheAddr[offset] = CACHE_MISS; |
| 537 | return; |
| 538 | } |
| 539 | cacheAddr[offset] = address >> 12; |
| 540 | cacheData[offset] = value; |
| 541 | } |
| 542 | |
| 543 | #define mem_read cache_read |
| 544 | #define mem_write cache_write |
| 545 | #endif //SIMPLE_CACHE |
| 546 | /************* End optional cache implementation *************/ |
| 547 | |
| 548 | |
| 549 | void mult_big(unsigned int a, |
| 550 | unsigned int b, |
| 551 | unsigned int *hi, |
| 552 | unsigned int *lo) |
| 553 | { |
| 554 | unsigned int ahi, alo, bhi, blo; |
| 555 | unsigned int c0, c1, c2; |
| 556 | unsigned int c1_a, c1_b; |
| 557 | |
| 558 | ahi = a >> 16; |
| 559 | alo = a & 0xffff; |
| 560 | bhi = b >> 16; |
| 561 | blo = b & 0xffff; |
| 562 | |
| 563 | c0 = alo * blo; |
| 564 | c1_a = ahi * blo; |
| 565 | c1_b = alo * bhi; |
| 566 | c2 = ahi * bhi; |
| 567 | |
| 568 | c2 += (c1_a >> 16) + (c1_b >> 16); |
| 569 | c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16); |
| 570 | c2 += (c1 >> 16); |
| 571 | c0 = (c1 << 16) + (c0 & 0xffff); |
| 572 | *hi = c2; |
| 573 | *lo = c0; |
| 574 | } |
| 575 | |
| 576 | void mult_big_signed(int a, |
| 577 | int b, |
| 578 | unsigned int *hi, |
| 579 | unsigned int *lo) |
| 580 | { |
| 581 | unsigned int ahi, alo, bhi, blo; |
| 582 | unsigned int c0, c1, c2; |
| 583 | unsigned int c1_a, c1_b; |
| 584 | |
| 585 | ahi = a >> 16; |
| 586 | alo = a & 0xffff; |
| 587 | bhi = b >> 16; |
| 588 | blo = b & 0xffff; |
| 589 | |
| 590 | c0 = alo * blo; |
| 591 | c1_a = ahi * blo; |
| 592 | c1_b = alo * bhi; |
| 593 | c2 = ahi * bhi; |
| 594 | |
| 595 | c2 += (c1_a >> 16) + (c1_b >> 16); |
| 596 | c1 = (c1_a & 0xffff) + (c1_b & 0xffff) + (c0 >> 16); |
| 597 | c2 += (c1 >> 16); |
| 598 | c0 = (c1 << 16) + (c0 & 0xffff); |
| 599 | *hi = c2; |
| 600 | *lo = c0; |
| 601 | } |
| 602 | |
| 603 | //execute one cycle of a Plasma CPU |
| 604 | void cycle(State *s, int show_mode) |
| 605 | { |
| 606 | unsigned int opcode; |
| 607 | unsigned int op, rs, rt, rd, re, func, imm, target; |
| 608 | int imm_shift, branch=0, lbranch=2, skip2=0; |
| 609 | int *r=s->r; |
| 610 | unsigned int *u=(unsigned int*)s->r; |
| 611 | unsigned int ptr, epc, rSave; |
| 612 | |
| 613 | opcode = mem_read(s, 4, s->pc); |
| 614 | op = (opcode >> 26) & 0x3f; |
| 615 | rs = (opcode >> 21) & 0x1f; |
| 616 | rt = (opcode >> 16) & 0x1f; |
| 617 | rd = (opcode >> 11) & 0x1f; |
| 618 | re = (opcode >> 6) & 0x1f; |
| 619 | func = opcode & 0x3f; |
| 620 | imm = opcode & 0xffff; |
| 621 | imm_shift = (((int)(short)imm) << 2) - 4; |
| 622 | target = (opcode << 6) >> 4; |
| 623 | ptr = (short)imm + r[rs]; |
| 624 | r[0] = 0; |
| 625 | if(show_mode) |
| 626 | { |
| 627 | printf("%8.8x %8.8x ", s->pc, opcode); |
| 628 | if(op == 0) |
| 629 | printf("%8s ", special_string[func]); |
| 630 | else if(op == 1) |
| 631 | printf("%8s ", regimm_string[rt]); |
| 632 | else |
| 633 | printf("%8s ", opcode_string[op]); |
| 634 | printf("$%2.2d $%2.2d $%2.2d $%2.2d ", rs, rt, rd, re); |
| 635 | printf("%4.4x", imm); |
| 636 | if(show_mode == 1) |
| 637 | printf(" r[%2.2d]=%8.8x r[%2.2d]=%8.8x", rs, r[rs], rt, r[rt]); |
| 638 | printf("\n"); |
| 639 | } |
| 640 | if(show_mode > 5) |
| 641 | return; |
| 642 | epc = s->pc + 4; |
| 643 | if(s->pc_next != s->pc + 4) |
| 644 | epc |= 2; //branch delay slot |
| 645 | s->pc = s->pc_next; |
| 646 | s->pc_next = s->pc_next + 4; |
| 647 | if(s->skip) |
| 648 | { |
| 649 | s->skip = 0; |
| 650 | return; |
| 651 | } |
| 652 | rSave = r[rt]; |
| 653 | switch(op) |
| 654 | { |
| 655 | case 0x00:/*SPECIAL*/ |
| 656 | switch(func) |
| 657 | { |
| 658 | case 0x00:/*SLL*/ r[rd]=r[rt]<<re; break; |
| 659 | case 0x02:/*SRL*/ r[rd]=u[rt]>>re; break; |
| 660 | case 0x03:/*SRA*/ r[rd]=r[rt]>>re; break; |
| 661 | case 0x04:/*SLLV*/ r[rd]=r[rt]<<r[rs]; break; |
| 662 | case 0x06:/*SRLV*/ r[rd]=u[rt]>>r[rs]; break; |
| 663 | case 0x07:/*SRAV*/ r[rd]=r[rt]>>r[rs]; break; |
| 664 | case 0x08:/*JR*/ s->pc_next=r[rs]; break; |
| 665 | case 0x09:/*JALR*/ r[rd]=s->pc_next; s->pc_next=r[rs]; break; |
| 666 | case 0x0a:/*MOVZ*/ if(!r[rt]) r[rd]=r[rs]; break; /*IV*/ |
| 667 | case 0x0b:/*MOVN*/ if(r[rt]) r[rd]=r[rs]; break; /*IV*/ |
| 668 | case 0x0c:/*SYSCALL*/ epc|=1; s->exceptionId=1; break; |
| 669 | case 0x0d:/*BREAK*/ epc|=1; s->exceptionId=1; break; |
| 670 | case 0x0f:/*SYNC*/ s->wakeup=1; break; |
| 671 | case 0x10:/*MFHI*/ r[rd]=s->hi; break; |
| 672 | case 0x11:/*FTHI*/ s->hi=r[rs]; break; |
| 673 | case 0x12:/*MFLO*/ r[rd]=s->lo; break; |
| 674 | case 0x13:/*MTLO*/ s->lo=r[rs]; break; |
| 675 | case 0x18:/*MULT*/ mult_big_signed(r[rs],r[rt],&s->hi,&s->lo); break; |
| 676 | case 0x19:/*MULTU*/ mult_big(r[rs],r[rt],&s->hi,&s->lo); break; |
| 677 | case 0x1a:/*DIV*/ s->lo=r[rs]/r[rt]; s->hi=r[rs]%r[rt]; break; |
| 678 | case 0x1b:/*DIVU*/ s->lo=u[rs]/u[rt]; s->hi=u[rs]%u[rt]; break; |
| 679 | case 0x20:/*ADD*/ r[rd]=r[rs]+r[rt]; break; |
| 680 | case 0x21:/*ADDU*/ r[rd]=r[rs]+r[rt]; break; |
| 681 | case 0x22:/*SUB*/ r[rd]=r[rs]-r[rt]; break; |
| 682 | case 0x23:/*SUBU*/ r[rd]=r[rs]-r[rt]; break; |
| 683 | case 0x24:/*AND*/ r[rd]=r[rs]&r[rt]; break; |
| 684 | case 0x25:/*OR*/ r[rd]=r[rs]|r[rt]; break; |
| 685 | case 0x26:/*XOR*/ r[rd]=r[rs]^r[rt]; break; |
| 686 | case 0x27:/*NOR*/ r[rd]=~(r[rs]|r[rt]); break; |
| 687 | case 0x2a:/*SLT*/ r[rd]=r[rs]<r[rt]; break; |
| 688 | case 0x2b:/*SLTU*/ r[rd]=u[rs]<u[rt]; break; |
| 689 | case 0x2d:/*DADDU*/r[rd]=r[rs]+u[rt]; break; |
| 690 | case 0x31:/*TGEU*/ break; |
| 691 | case 0x32:/*TLT*/ break; |
| 692 | case 0x33:/*TLTU*/ break; |
| 693 | case 0x34:/*TEQ*/ break; |
| 694 | case 0x36:/*TNE*/ break; |
| 695 | default: printf("ERROR0(*0x%x~0x%x)\n", s->pc, opcode); |
| 696 | s->wakeup=1; |
| 697 | } |
| 698 | break; |
| 699 | case 0x01:/*REGIMM*/ |
| 700 | switch(rt) { |
| 701 | case 0x10:/*BLTZAL*/ r[31]=s->pc_next; |
| 702 | case 0x00:/*BLTZ*/ branch=r[rs]<0; break; |
| 703 | case 0x11:/*BGEZAL*/ r[31]=s->pc_next; |
| 704 | case 0x01:/*BGEZ*/ branch=r[rs]>=0; break; |
| 705 | case 0x12:/*BLTZALL*/r[31]=s->pc_next; |
| 706 | case 0x02:/*BLTZL*/ lbranch=r[rs]<0; break; |
| 707 | case 0x13:/*BGEZALL*/r[31]=s->pc_next; |
| 708 | case 0x03:/*BGEZL*/ lbranch=r[rs]>=0; break; |
| 709 | default: printf("ERROR1\n"); s->wakeup=1; |
| 710 | } |
| 711 | break; |
| 712 | case 0x03:/*JAL*/ r[31]=s->pc_next; |
| 713 | case 0x02:/*J*/ s->pc_next=(s->pc&0xf0000000)|target; break; |
| 714 | case 0x04:/*BEQ*/ branch=r[rs]==r[rt]; break; |
| 715 | case 0x05:/*BNE*/ branch=r[rs]!=r[rt]; break; |
| 716 | case 0x06:/*BLEZ*/ branch=r[rs]<=0; break; |
| 717 | case 0x07:/*BGTZ*/ branch=r[rs]>0; break; |
| 718 | case 0x08:/*ADDI*/ r[rt]=r[rs]+(short)imm; break; |
| 719 | case 0x09:/*ADDIU*/ u[rt]=u[rs]+(short)imm; break; |
| 720 | case 0x0a:/*SLTI*/ r[rt]=r[rs]<(short)imm; break; |
| 721 | case 0x0b:/*SLTIU*/ u[rt]=u[rs]<(unsigned int)(short)imm; break; |
| 722 | case 0x0c:/*ANDI*/ r[rt]=r[rs]&imm; break; |
| 723 | case 0x0d:/*ORI*/ r[rt]=r[rs]|imm; break; |
| 724 | case 0x0e:/*XORI*/ r[rt]=r[rs]^imm; break; |
| 725 | case 0x0f:/*LUI*/ r[rt]=(imm<<16); break; |
| 726 | case 0x10:/*COP0*/ |
| 727 | if((opcode & (1<<23)) == 0) //move from CP0 |
| 728 | { |
| 729 | if(rd == 12) |
| 730 | r[rt]=s->status; |
| 731 | else |
| 732 | r[rt]=s->epc; |
| 733 | } |
| 734 | else //move to CP0 |
| 735 | { |
| 736 | s->status=r[rt]&1; |
| 737 | if(s->processId && (r[rt]&2)) |
| 738 | { |
| 739 | s->userMode|=r[rt]&2; |
| 740 | //printf("CpuStatus=%d %d %d\n", r[rt], s->status, s->userMode); |
| 741 | //s->wakeup = 1; |
| 742 | //printf("pc=0x%x\n", epc); |
| 743 | } |
| 744 | } |
| 745 | break; |
| 746 | // case 0x11:/*COP1*/ break; |
| 747 | // case 0x12:/*COP2*/ break; |
| 748 | // case 0x13:/*COP3*/ break; |
| 749 | case 0x14:/*BEQL*/ lbranch=r[rs]==r[rt]; break; |
| 750 | case 0x15:/*BNEL*/ lbranch=r[rs]!=r[rt]; break; |
| 751 | case 0x16:/*BLEZL*/ lbranch=r[rs]<=0; break; |
| 752 | case 0x17:/*BGTZL*/ lbranch=r[rs]>0; break; |
| 753 | // case 0x1c:/*MAD*/ break; /*IV*/ |
| 754 | case 0x20:/*LB*/ r[rt]=(signed char)mem_read(s,1,ptr); break; |
| 755 | case 0x21:/*LH*/ r[rt]=(signed short)mem_read(s,2,ptr); break; |
| 756 | case 0x22:/*LWL*/ |
| 757 | //target=8*(ptr&3); |
| 758 | //r[rt]=(r[rt]&~(0xffffffff<<target))| |
| 759 | // (mem_read(s,4,ptr&~3)<<target); break; |
| 760 | case 0x23:/*LW*/ r[rt]=mem_read(s,4,ptr); break; |
| 761 | case 0x24:/*LBU*/ r[rt]=(unsigned char)mem_read(s,1,ptr); break; |
| 762 | case 0x25:/*LHU*/ r[rt]=(unsigned short)mem_read(s,2,ptr); break; |
| 763 | case 0x26:/*LWR*/ |
| 764 | //target=32-8*(ptr&3); |
| 765 | //r[rt]=(r[rt]&~((unsigned int)0xffffffff>>target))| |
| 766 | //((unsigned int)mem_read(s,4,ptr&~3)>>target); |
| 767 | break; |
| 768 | case 0x28:/*SB*/ mem_write(s,1,ptr,r[rt]); break; |
| 769 | case 0x29:/*SH*/ mem_write(s,2,ptr,r[rt]); break; |
| 770 | case 0x2a:/*SWL*/ |
| 771 | //mem_write(s,1,ptr,r[rt]>>24); |
| 772 | //mem_write(s,1,ptr+1,r[rt]>>16); |
| 773 | //mem_write(s,1,ptr+2,r[rt]>>8); |
| 774 | //mem_write(s,1,ptr+3,r[rt]); break; |
| 775 | case 0x2b:/*SW*/ mem_write(s,4,ptr,r[rt]); break; |
| 776 | case 0x2e:/*SWR*/ break; //fixme |
| 777 | case 0x2f:/*CACHE*/break; |
| 778 | case 0x30:/*LL*/ r[rt]=mem_read(s,4,ptr); break; |
| 779 | // case 0x31:/*LWC1*/ break; |
| 780 | // case 0x32:/*LWC2*/ break; |
| 781 | // case 0x33:/*LWC3*/ break; |
| 782 | // case 0x35:/*LDC1*/ break; |
| 783 | // case 0x36:/*LDC2*/ break; |
| 784 | // case 0x37:/*LDC3*/ break; |
| 785 | // case 0x38:/*SC*/ *(int*)ptr=r[rt]; r[rt]=1; break; |
| 786 | case 0x38:/*SC*/ mem_write(s,4,ptr,r[rt]); r[rt]=1; break; |
| 787 | // case 0x39:/*SWC1*/ break; |
| 788 | // case 0x3a:/*SWC2*/ break; |
| 789 | // case 0x3b:/*SWC3*/ break; |
| 790 | // case 0x3d:/*SDC1*/ break; |
| 791 | // case 0x3e:/*SDC2*/ break; |
| 792 | // case 0x3f:/*SDC3*/ break; |
| 793 | default: printf("ERROR2 address=0x%x opcode=0x%x\n", s->pc, opcode); |
| 794 | s->wakeup=1; |
| 795 | } |
| 796 | s->pc_next += (branch || lbranch == 1) ? imm_shift : 0; |
| 797 | s->pc_next &= ~3; |
| 798 | s->skip = (lbranch == 0) | skip2; |
| 799 | |
| 800 | if(s->exceptionId) |
| 801 | { |
| 802 | r[rt] = rSave; |
| 803 | s->epc = epc; |
| 804 | s->pc_next = 0x3c; |
| 805 | s->skip = 1; |
| 806 | s->exceptionId = 0; |
| 807 | s->userMode = 0; |
| 808 | //s->wakeup = 1; |
| 809 | return; |
| 810 | } |
| 811 | } |
| 812 | |
| 813 | void show_state(State *s) |
| 814 | { |
| 815 | int i,j; |
| 816 | printf("pid=%d userMode=%d, epc=0x%x\n", s->processId, s->userMode, s->epc); |
| 817 | for(i = 0; i < 4; ++i) |
| 818 | { |
| 819 | printf("%2.2d ", i * 8); |
| 820 | for(j = 0; j < 8; ++j) |
| 821 | { |
| 822 | printf("%8.8x ", s->r[i*8+j]); |
| 823 | } |
| 824 | printf("\n"); |
| 825 | } |
| 826 | //printf("%8.8lx %8.8lx %8.8lx %8.8lx\n", s->pc, s->pc_next, s->hi, s->lo); |
| 827 | j = s->pc; |
| 828 | for(i = -4; i <= 8; ++i) |
| 829 | { |
| 830 | printf("%c", i==0 ? '*' : ' '); |
| 831 | s->pc = j + i * 4; |
| 832 | cycle(s, 10); |
| 833 | } |
| 834 | s->pc = j; |
| 835 | } |
| 836 | |
| 837 | void do_debug(State *s) |
| 838 | { |
| 839 | int ch; |
| 840 | int i, j=0, watch=0, addr; |
| 841 | s->pc_next = s->pc + 4; |
| 842 | s->skip = 0; |
| 843 | s->wakeup = 0; |
| 844 | show_state(s); |
| 845 | ch = ' '; |
| 846 | for(;;) |
| 847 | { |
| 848 | if(ch != 'n') |
| 849 | { |
| 850 | if(watch) |
| 851 | printf("0x%8.8x=0x%8.8x\n", watch, mem_read(s, 4, watch)); |
| 852 | printf("1=Debug 2=Trace 3=Step 4=BreakPt 5=Go 6=Memory "); |
| 853 | printf("7=Watch 8=Jump 9=Quit> "); |
| 854 | } |
| 855 | ch = getch(); |
| 856 | if(ch != 'n') |
| 857 | printf("\n"); |
| 858 | switch(ch) |
| 859 | { |
| 860 | case '1': case 'd': case ' ': |
| 861 | cycle(s, 0); show_state(s); break; |
| 862 | case 'n': |
| 863 | cycle(s, 1); break; |
| 864 | case '2': case 't': |
| 865 | cycle(s, 0); printf("*"); cycle(s, 10); break; |
| 866 | case '3': case 's': |
| 867 | printf("Count> "); |
| 868 | scanf("%d", &j); |
| 869 | for(i = 0; i < j; ++i) |
| 870 | cycle(s, 1); |
| 871 | show_state(s); |
| 872 | break; |
| 873 | case '4': case 'b': |
| 874 | printf("Line> "); |
| 875 | scanf("%x", &j); |
| 876 | printf("break point=0x%x\n", j); |
| 877 | break; |
| 878 | case '5': case 'g': |
| 879 | s->wakeup = 0; |
| 880 | cycle(s, 0); |
| 881 | while(s->wakeup == 0) |
| 882 | { |
| 883 | if(s->pc == j) |
| 884 | break; |
| 885 | cycle(s, 0); |
| 886 | } |
| 887 | show_state(s); |
| 888 | break; |
| 889 | case 'G': |
| 890 | s->wakeup = 0; |
| 891 | cycle(s, 1); |
| 892 | while(s->wakeup == 0) |
| 893 | { |
| 894 | if(s->pc == j) |
| 895 | break; |
| 896 | cycle(s, 1); |
| 897 | } |
| 898 | show_state(s); |
| 899 | break; |
| 900 | case '6': case 'm': |
| 901 | printf("Memory> "); |
| 902 | scanf("%x", &j); |
| 903 | for(i = 0; i < 8; ++i) |
| 904 | { |
| 905 | printf("%8.8x ", mem_read(s, 4, j+i*4)); |
| 906 | } |
| 907 | printf("\n"); |
| 908 | break; |
| 909 | case '7': case 'w': |
| 910 | printf("Watch> "); |
| 911 | scanf("%x", &watch); |
| 912 | break; |
| 913 | case '8': case 'j': |
| 914 | printf("Jump> "); |
| 915 | scanf("%x", &addr); |
| 916 | s->pc = addr; |
| 917 | s->pc_next = addr + 4; |
| 918 | show_state(s); |
| 919 | break; |
| 920 | case '9': case 'q': |
| 921 | return; |
| 922 | } |
| 923 | } |
| 924 | } |
| 925 | /************************************************************/ |
| 926 | |
| 927 | int main(int argc,char *argv[]) |
| 928 | { |
| 929 | State state, *s=&state; |
| 930 | FILE *in; |
| 931 | int bytes, index; |
| 932 | printf("Plasma emulator\n"); |
| 933 | memset(s, 0, sizeof(State)); |
| 934 | s->big_endian = 1; |
| 935 | s->mem = (unsigned char*)malloc(MEM_SIZE); |
| 936 | memset(s->mem, 0, MEM_SIZE); |
| 937 | if(argc <= 1) |
| 938 | { |
| 939 | printf(" Usage: mlite file.exe\n"); |
| 940 | printf(" mlite file.exe B {for big_endian}\n"); |
| 941 | printf(" mlite file.exe L {for little_endian}\n"); |
| 942 | printf(" mlite file.exe BD {disassemble big_endian}\n"); |
| 943 | printf(" mlite file.exe LD {disassemble little_endian}\n"); |
| 944 | |
| 945 | return 0; |
| 946 | } |
| 947 | in = fopen(argv[1], "rb"); |
| 948 | if(in == NULL) |
| 949 | { |
| 950 | printf("Can't open file %s!\n",argv[1]); |
| 951 | getch(); |
| 952 | return(0); |
| 953 | } |
| 954 | bytes = fread(s->mem, 1, MEM_SIZE, in); |
| 955 | fclose(in); |
| 956 | memcpy(s->mem + 1024*1024, s->mem, 1024*1024); //internal 8KB SRAM |
| 957 | printf("Read %d bytes.\n", bytes); |
| 958 | cache_init(); |
| 959 | if(argc == 3 && argv[2][0] == 'B') |
| 960 | { |
| 961 | printf("Big Endian\n"); |
| 962 | s->big_endian = 1; |
| 963 | } |
| 964 | if(argc == 3 && argv[2][0] == 'L') |
| 965 | { |
| 966 | printf("Big Endian\n"); |
| 967 | s->big_endian = 0; |
| 968 | } |
| 969 | s->processId = 0; |
| 970 | if(argc == 3 && argv[2][0] == 'S') |
| 971 | { /*make big endian*/ |
| 972 | printf("Big Endian\n"); |
| 973 | for(index = 0; index < bytes+3; index += 4) |
| 974 | { |
| 975 | *(unsigned int*)&s->mem[index] = htonl(*(unsigned int*)&s->mem[index]); |
| 976 | } |
| 977 | in = fopen("big.exe", "wb"); |
| 978 | fwrite(s->mem, bytes, 1, in); |
| 979 | fclose(in); |
| 980 | return(0); |
| 981 | } |
| 982 | if(argc == 3 && argv[2][1] == 'D') |
| 983 | { /*dump image*/ |
| 984 | for(index = 0; index < bytes; index += 4) { |
| 985 | s->pc = index; |
| 986 | cycle(s, 10); |
| 987 | } |
| 988 | free(s->mem); |
| 989 | return(0); |
| 990 | } |
| 991 | s->pc = 0x0; |
| 992 | index = mem_read(s, 4, 0); |
| 993 | if((index & 0xffffff00) == 0x3c1c1000) |
| 994 | s->pc = 0x10000000; |
| 995 | do_debug(s); |
| 996 | free(s->mem); |
| 997 | return(0); |
| 998 | } |
| 999 | |