#include "VBriey.h" #include "VBriey_Briey.h" //#include "VBriey_Axi4VgaCtrl.h" //#include "VBriey_VgaCtrl.h" #ifdef REF #include "VBriey_RiscvCore.h" #endif #include "verilated.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "VBriey_VexRiscv.h" #include "../common/framework.h" #include "../common/jtag.h" #include "../common/uart.h" class SdramConfig{ public: uint32_t byteCount; uint32_t bankCount; uint32_t rowSize; uint32_t colSize; SdramConfig(uint32_t byteCount, uint32_t bankCount, uint32_t rowSize, uint32_t colSize){ this->byteCount = byteCount; this->bankCount = bankCount; this->rowSize = rowSize; this->colSize = colSize; } }; class SdramIo{ public: CData *BA; CData *DQM; CData *CASn; CData *CKE; CData *CSn; CData *RASn; CData *WEn; SData *ADDR; CData *DQ_read; CData *DQ_write; CData *DQ_writeEnable; }; class Sdram : public SimElement{ public: SdramConfig *config; SdramIo *io; uint32_t CAS; uint32_t burstLength; class Bank{ public: uint8_t *data; SdramConfig *config; bool opened; uint32_t openedRow; void init(SdramConfig *config){ this->config = config; data = new uint8_t[config->rowSize * config->colSize * config->byteCount]; opened = false; } virtual ~Bank(){ delete data; } void activate(uint32_t row){ if(opened) cout << "SDRAM error open unclosed bank" << endl; openedRow = row; opened = true; } void precharge(){ opened = false; } void write(uint32_t column, CData byteId, CData data){ if(!opened) cout << "SDRAM : write in closed bank" << endl; uint32_t addr = byteId + (column + openedRow * config->colSize) * config->byteCount; //printf("SDRAM : Write A=%08x D=%02x\n",addr,data); this->data[addr] = data; } CData read(uint32_t column, CData byteId){ if(!opened) cout << "SDRAM : write in closed bank" << endl; uint32_t addr = byteId + (column + openedRow * config->colSize) * config->byteCount; //printf("SDRAM : Read A=%08x D=%02x\n",addr,data[addr]); return data[addr]; } }; Bank* banks; CData * readShifter; Sdram(SdramConfig *config,SdramIo* io){ this->config = config; this->io = io; banks = new Bank[config->bankCount]; for(uint32_t bankId = 0;bankId < config->bankCount;bankId++) banks[bankId].init(config); readShifter = new CData[config->byteCount*3]; } virtual ~Sdram(){ delete banks; delete readShifter; } uint8_t ckeLast = 0; virtual void postCycle(){ if(CAS >= 2 && CAS <=3){ for(uint32_t byteId = 0;byteId != config->byteCount;byteId++){ io->DQ_read[byteId] = readShifter[byteId + (CAS-1)*config->byteCount]; } for(uint32_t latency = CAS-1;latency != 0;latency--){ //missing CKE for(uint32_t byteId = 0;byteId != config->byteCount;byteId++){ readShifter[byteId+latency*config->byteCount] = readShifter[byteId+(latency-1)*config->byteCount]; } } } } virtual void preCycle(){ if(!*io->CSn && ckeLast){ uint32_t code = ((*io->RASn) << 2) | ((*io->CASn) << 1) | ((*io->WEn) << 0); switch(code){ case 0: //Mode register set if(*io->BA == 0 && (*io->ADDR & 0x400) == 0){ CAS = ((*io->ADDR) >> 4) & 0x7; burstLength = ((*io->ADDR) >> 0) & 0x7; if((*io->ADDR & 0x388) != 0) cout << "SDRAM : ???" << endl; printf("SDRAM : MODE REGISTER DEFINITION CAS=%d burstLength=%d\n",CAS,burstLength); } break; case 2: //Bank precharge if((*io->ADDR & 0x400) != 0){ //all for(uint32_t bankId = 0;bankId < config->bankCount;bankId++) banks[bankId].precharge(); } else { //single banks[*io->BA].precharge(); } break; case 3: //Bank activate banks[*io->BA].activate(*io->ADDR & 0x7FF); break; case 4: //Write if((*io->ADDR & 0x400) != 0) cout << "SDRAM : Write autoprecharge not supported" << endl; if(*io->DQ_writeEnable == 0) cout << "SDRAM : Write Wrong DQ direction" << endl; for(uint32_t byteId = 0;byteId < config->byteCount;byteId++){ if(((*io->DQM >> byteId) & 1) == 0) banks[*io->BA].write(*io->ADDR, byteId ,io->DQ_write[byteId]); } break; case 5: //Read if((*io->ADDR & 0x400) != 0) cout << "SDRAM : READ autoprecharge not supported" << endl; if(*io->DQ_writeEnable != 0) cout << "SDRAM : READ Wrong DQ direction" << endl; //if(*io->DQM != config->byteCount-1) //cout << "SDRAM : READ wrong DQM" << endl; for(uint32_t byteId = 0;byteId < config->byteCount;byteId++){ readShifter[byteId] = banks[*io->BA].read(*io->ADDR, byteId); } break; case 1: // Self refresh break; case 7: // NOP break; default: cout << "SDRAM : unknown code" << endl; break; } } ckeLast = *io->CKE; } }; class VexRiscvTracer : public SimElement{ public: VBriey_VexRiscv *cpu; ofstream instructionTraces; ofstream regTraces; VexRiscvTracer(VBriey_VexRiscv *cpu){ this->cpu = cpu; #ifdef TRACE_INSTRUCTION instructionTraces.open ("instructionTrace.log"); #endif #ifdef TRACE_REG regTraces.open ("regTraces.log"); #endif } virtual void preCycle(){ #ifdef TRACE_INSTRUCTION if(cpu->writeBack_arbitration_isFiring){ instructionTraces << hex << setw(8) << cpu->writeBack_INSTRUCTION << endl; } #endif #ifdef TRACE_REG if(cpu->writeBack_RegFilePlugin_regFileWrite_valid == 1 && cpu->writeBack_RegFilePlugin_regFileWrite_payload_address != 0){ regTraces << " PC " << hex << setw(8) << cpu->writeBack_PC << " : reg[" << dec << setw(2) << (uint32_t)cpu->writeBack_RegFilePlugin_regFileWrite_payload_address << "] = " << hex << setw(8) << cpu->writeBack_RegFilePlugin_regFileWrite_payload_data << endl; } #endif } }; #include #include #include #include class Display : public SimElement{ public: int width, height; uint32_t *pixels; SDL_Window* window; SDL_Renderer* renderer; SDL_Texture * texture; uint32_t x,y; uint32_t refreshCounter = 0; Display(int width, int height){ this->width = width; this->height = height; x = y = 0; init(); } virtual ~Display(){ delete[] pixels; SDL_DestroyTexture(texture); SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); } void init(){ /* Initialize SDL. */ if (SDL_Init(SDL_INIT_VIDEO) < 0) return; /* Create the window where we will draw. */ window = SDL_CreateWindow("VGA", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_SHOWN); /* We must call SDL_CreateRenderer in order for draw calls to affect this window. */ renderer = SDL_CreateRenderer(window, -1, 0); texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC, width, height); pixels = new Uint32[width * height]; memset(pixels, 0, width * height * sizeof(Uint32)); } void set(uint32_t color){ pixels[x + y*width] = color; } void incX(){ x++; if(x >= width) x = width; } void incY(){ y++; if(y >= height) y = height; } void refresh(){ //cout << "Display refresh " << refreshCounter++ << endl; SDL_UpdateTexture(texture, NULL, pixels, 640 * sizeof(Uint32)); SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); memset(pixels, 0, width * height * sizeof(Uint32)); } virtual void postCycle(){ } virtual void preCycle(){ } }; class Vga : public Display{ public: VBriey* top; Vga(VBriey* top,int width, int height) : Display(width, height){ this->top = top; } virtual ~Vga(){ } virtual void postCycle(){ } uint32_t lastvSync = 0,lasthSync = 0; virtual void preCycle(){ if(!top->io_vga_vSync && lastvSync) { y = 0; refresh(); } if(!top->io_vga_hSync && lasthSync && x != 0) { incY(); x = 0; } if(top->io_vga_colorEn){ this->set((top->io_vga_color_r << 19) + (top->io_vga_color_g << 10) + (top->io_vga_color_b << 3)); incX(); } lastvSync = top->io_vga_vSync; lasthSync = top->io_vga_hSync; } }; class BrieyWorkspace : public Workspace{ public: BrieyWorkspace() : Workspace("Briey"){ ClockDomain *axiClk = new ClockDomain(&top->io_axiClk,NULL,20000,100000); ClockDomain *vgaClk = new ClockDomain(&top->io_vgaClk,NULL,40000,100000); AsyncReset *asyncReset = new AsyncReset(&top->io_asyncReset,50000); Jtag *jtag = new Jtag(&top->io_jtag_tms,&top->io_jtag_tdi,&top->io_jtag_tdo,&top->io_jtag_tck,80000); UartRx *uartRx = new UartRx(&top->io_uart_txd,1.0e12/115200); timeProcesses.push_back(axiClk); timeProcesses.push_back(vgaClk); timeProcesses.push_back(asyncReset); timeProcesses.push_back(jtag); timeProcesses.push_back(uartRx); top->io_uart_rxd = 1; SdramConfig *sdramConfig = new SdramConfig( 2, //byteCount 4, //bankCount 1 << 13, //rowSize 1 << 10 //colSize ); SdramIo *sdramIo = new SdramIo(); sdramIo->BA = &top->io_sdram_BA ; sdramIo->DQM = &top->io_sdram_DQM ; sdramIo->CASn = &top->io_sdram_CASn ; sdramIo->CKE = &top->io_sdram_CKE ; sdramIo->CSn = &top->io_sdram_CSn ; sdramIo->RASn = &top->io_sdram_RASn ; sdramIo->WEn = &top->io_sdram_WEn ; sdramIo->ADDR = &top->io_sdram_ADDR ; sdramIo->DQ_read = (CData*)&top->io_sdram_DQ_read ; sdramIo->DQ_write = (CData*)&top->io_sdram_DQ_write ; sdramIo->DQ_writeEnable = (CData*)&top->io_sdram_DQ_writeEnable; Sdram *sdram = new Sdram(sdramConfig, sdramIo); axiClk->add(sdram); #ifdef TRACE //speedFactor = 100e-6; //cout << "Simulation caped to " << timeToSec << " of real time"<< endl; #endif axiClk->add(new VexRiscvTracer(top->Briey->axi_core_cpu)); #ifdef VGA Vga *vga = new Vga(top,640,480); vgaClk->add(vga); #endif top->io_coreInterrupt = 0; } /*bool trigged = false; uint32_t frameStartCounter = 0; virtual void dump(uint64_t i){ if(!trigged) { if(top->Briey->axi_vgaCtrl->vga_ctrl->io_frameStart) { frameStartCounter++; if(frameStartCounter < 3*32) cout << "**\n" << endl; } if(top->Briey->axi_vgaCtrl->vga_ctrl->io_error && frameStartCounter > 3*32) trigged = true; } if(trigged)Workspace::dump(i); }*/ }; struct timespec timer_start(){ struct timespec start_time; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &start_time); return start_time; } long timer_end(struct timespec start_time){ struct timespec end_time; clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end_time); uint64_t diffInNanos = end_time.tv_sec*1e9 + end_time.tv_nsec - start_time.tv_sec*1e9 - start_time.tv_nsec; return diffInNanos; } int main(int argc, char **argv, char **env) { Verilated::randReset(2); Verilated::commandArgs(argc, argv); printf("BOOT\n"); timespec startedAt = timer_start(); BrieyWorkspace().run(1e9); uint64_t duration = timer_end(startedAt); cout << endl << "****************************************************************" << endl; exit(0); }