Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
6abc6ec19This file is pinned to the selected release. Download the original to open it in your design tool.
#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 <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <stdint.h>
#include <cstring>
#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <iomanip>
#include <time.h>
#include <unistd.h>
#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 <SDL2/SDL.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
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<VBriey>{
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);
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;
cout << "Had simulate " << workspaceCycles << " clock cycles in " << duration*1e-9 << " s (" << workspaceCycles / (duration*1e-9) << " Khz)" << endl;
cout << "****************************************************************" << endl << endl;
exit(0);
}