module M_%MODULE%_mem_%NAME%(
input      [%WENABLE0_WIDTH%:0]             in_%NAME%_wenable0,
input      %DATA_TYPE% [%DATA_WIDTH%:0]     in_%NAME%_wdata0,
input      [%ADDR0_WIDTH%:0]                in_%NAME%_addr0,
input      [%WENABLE1_WIDTH%:0]             in_%NAME%_wenable1,
input      [%DATA_WIDTH%:0]                 in_%NAME%_wdata1,
input      [%ADDR1_WIDTH%:0]                in_%NAME%_addr1,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]     out_%NAME%_rdata0,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]     out_%NAME%_rdata1,
input      %CLOCK%0,
input      %CLOCK%1
);
reg %DATA_TYPE% [%DATA_WIDTH%:0] buffer[%DATA_SIZE%:0];
always @(posedge %CLOCK%0) begin
  out_%NAME%_rdata0 <= buffer[in_%NAME%_addr0];
  if (in_%NAME%_wenable0) begin
    out_%NAME%_rdata0       <= in_%NAME%_wdata0;
    buffer[in_%NAME%_addr0] <= in_%NAME%_wdata0;
  end
end
always @(posedge %CLOCK%1) begin
  out_%NAME%_rdata1 <= buffer[in_%NAME%_addr1];
  if (in_%NAME%_wenable1) begin
    out_%NAME%_rdata1       <= in_%NAME%_wdata1;
    buffer[in_%NAME%_addr1] <= in_%NAME%_wdata1;
  end
end
%INITIAL%
endmodule
module M_%MODULE%_mem_%NAME%(
input                  [%WENABLE_WIDTH%:0] in_%NAME%_wenable,
input      %DATA_TYPE% [%DATA_WIDTH%:0]    in_%NAME%_wdata,
input                  [%ADDR_WIDTH%:0]    in_%NAME%_addr,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]    out_%NAME%_rdata,
input                                      %CLOCK%
);
reg %DATA_TYPE% [%DATA_WIDTH%:0] buffer[%DATA_SIZE%:0];
always @(posedge %CLOCK%) begin
  if (in_%NAME%_wenable) begin
    buffer[in_%NAME%_addr] <= in_%NAME%_wdata;
  end
  out_%NAME%_rdata <= buffer[in_%NAME%_addr];
end
%INITIAL%
endmodule
module M_%MODULE%_mem_%NAME%(
input      [%WENABLE0_WIDTH%:0]             in_%NAME%_wenable0,
input      %DATA_TYPE% [%DATA_WIDTH%:0]     in_%NAME%_wdata0,
input      [%ADDR0_WIDTH%:0]                in_%NAME%_addr0,
input      [%WENABLE1_WIDTH%:0]             in_%NAME%_wenable1,
input      [%DATA_WIDTH%:0]                 in_%NAME%_wdata1,
input      [%ADDR1_WIDTH%:0]                in_%NAME%_addr1,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]     out_%NAME%_rdata0,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]     out_%NAME%_rdata1,
input      %CLOCK%0,
input      %CLOCK%1
);
reg %DATA_TYPE% [%DATA_WIDTH%:0] buffer[%DATA_SIZE%:0];
always @(posedge %CLOCK%0) begin
  if (in_%NAME%_wenable0) begin
    buffer[in_%NAME%_addr0] <= in_%NAME%_wdata0;
  end else begin
    out_%NAME%_rdata0 <= buffer[in_%NAME%_addr0];
  end
end
always @(posedge %CLOCK%1) begin
  if (in_%NAME%_wenable1) begin
    buffer[in_%NAME%_addr1] <= in_%NAME%_wdata1;
  end else begin
    out_%NAME%_rdata1 <= buffer[in_%NAME%_addr1];
  end
end
%INITIAL%
endmodule
module M_%MODULE%_mem_%NAME%(
input      [%ADDR0_WIDTH%:0]                in_%NAME%_addr0,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]     out_%NAME%_rdata0,
output reg %DATA_TYPE% [%DATA_WIDTH%:0]     out_%NAME%_rdata1,
input      [%WENABLE1_WIDTH%:0]             in_%NAME%_wenable1,
input      [%DATA_WIDTH%:0]                 in_%NAME%_wdata1,
input      [%ADDR1_WIDTH%:0]                in_%NAME%_addr1,
input      %CLOCK%0,
input      %CLOCK%1
);
reg %DATA_TYPE% [%DATA_WIDTH%:0] buffer[%DATA_SIZE%:0];
always @(posedge %CLOCK%0) begin
  out_%NAME%_rdata0 <= buffer[in_%NAME%_addr0];
end
always @(posedge %CLOCK%1) begin
  if (in_%NAME%_wenable1) begin
    buffer[in_%NAME%_addr1] <= in_%NAME%_wdata1;
  end
end
%INITIAL%
endmodule
module M_%MODULE%_mem_%NAME%(
input                  [%ADDR_WIDTH%:0] in_%NAME%_addr,
output reg %DATA_TYPE% [%DATA_WIDTH%:0] out_%NAME%_rdata,
input                                   %CLOCK%
);
reg %DATA_TYPE% [%DATA_WIDTH%:0] buffer[%DATA_SIZE%:0];
always @(posedge %CLOCK%) begin
   out_%NAME%_rdata <= buffer[in_%NAME%_addr];
end
%INITIAL%
endmodule
// ----------------------- memory_ports.ice -----------
// @sylefeb - Silice standard library
// Memory port interfaces
// 2020-09-03

// single port BRAM

interface bram_port {
  output! addr,
  output! wenable,
  input   rdata,
  output! wdata,
}

// single port BROM

interface brom_port {
  output! addr,
  input   rdata,
}

// dual port BRAM

interface dualbram_port0 {
  output! addr0,
  output! wenable0,
  input   rdata0,
  output! wdata0,
}

interface dualbram_port1 {
  output! addr1,
  output! wenable1,
  input   rdata1,
  output! wdata1,
}

// simple dual port BRAM

interface simple_dualbram_port0 {
  output! addr0,
  input   rdata0,
}

interface simple_dualbram_port1 {
  output! addr1,
  output! wenable1,
  output! wdata1,
}

interface bram_ports {
  output! addr0,
  output! wenable0,
  input   rdata0,
  output! wdata0,
  output! addr1,
  output! wenable1,
  input   rdata1,
  output! wdata1,
}

// ----------------------- end of memory_ports.ice ----
/*

    Silice FPGA language and compiler
    (c) Sylvain Lefebvre - @sylefeb

This work and all associated files are under the

     GNU AFFERO GENERAL PUBLIC LICENSE
        Version 3, 19 November 2007
        
A copy of the license full text is included in 
the distribution, please refer to it for details.

(header_1_0)
*/
// Sylvain Lefebvre 2019-09-26

#include "VgaChip.h"
#include "video_out.h"

VgaChip::VgaChip(int color_depth)
{
  m_VideoOut = new VideoOut(
        0/*debug*/,color_depth/*color depth*/,0/*polarity*/,
        640 ,16,96,48,
        480 ,10,2,33,
        "vgaout");
}

VgaChip::~VgaChip()
{
  delete (m_VideoOut);
}

void VgaChip::eval(
            vluint8_t  clk,
            vluint8_t  vs,
            vluint8_t  hs,
            vluint8_t  red,
            vluint8_t  green,
            vluint8_t  blue)
{
  m_VideoOut->eval_RGB_HV(clk,vs,hs,red,green,blue);
}

/*

    Silice FPGA language and compiler
    (c) Sylvain Lefebvre - @sylefeb

This work and all associated files are under the

     GNU AFFERO GENERAL PUBLIC LICENSE
        Version 3, 19 November 2007
        
A copy of the license full text is included in 
the distribution, please refer to it for details.

(header_1_0)
*/
//
// Based on code from the MCC216 project (https://github.com/fredrequin/fpga_1943)
// (c) Frederic Requin, GPL v3 license
//

#include "verilated.h"
#include "video_out.h"
#include "LibSL/Image/Image.h"
#include "LibSL/Image/ImageFormat_TGA.h"
#include "LibSL/Math/Vertex.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

using namespace LibSL::Image;
using namespace LibSL::Math;

ImageFormat_TGA g_RegisterFormat_TGA;

// Constructor 
VideoOut::VideoOut(vluint8_t debug, vluint8_t depth, vluint8_t polarity,
                   vluint16_t hactive, vluint16_t hfporch_, vluint16_t hspulse_, vluint16_t hbporch_,
                   vluint16_t vactive, vluint16_t vfporch_, vluint16_t vspulse_, vluint16_t vbporch_,
                   const char *file)
{
    // color depth
    if (depth <= 8) {
        bit_mask  = (1 << depth) - 1;
        bit_shift = (int)(8 - depth);
    } else {
        bit_mask  = (vluint8_t)0xFF;
        bit_shift = (int)0;
    }
    // synchros polarities
    hs_pol      = (polarity & HS_POS_POL) ? (vluint8_t)1 : (vluint8_t)0;
    vs_pol      = (polarity & VS_POS_POL) ? (vluint8_t)1 : (vluint8_t)0;
    // screen format initialized
    hor_size    = hactive;
    ver_size    = vactive;
    // record synch values
    hfporch = hfporch_;
    hspulse = hspulse_;
    hbporch = hbporch_;
    vfporch = vfporch_;
    vspulse = vspulse_;
    vbporch = vbporch_;
    // debug mode
    dbg_on      = debug;
    // allocate the pixels
    std::cerr << hactive << " x " << vactive << " x " << (int)depth << std::endl;
    pixels.allocate((int)hactive, (int)vactive);
    // copy the filename
    filename    = std::string(file);
    // internal variables cleared
    hcount      = (vluint16_t)hor_size;
    vcount      = (vluint16_t)ver_size;
    prev_clk    = (vluint8_t)0;
    prev_hs     = (vluint8_t)0;
    prev_vs     = (vluint8_t)0;
    dump_ctr    = (int)0;
    // synch
    v_sync_stage = e_Front;
    h_sync_stage = e_Front;
    v_sync_count = 0;
    h_sync_count = 0;
}

// Destructor
VideoOut::~VideoOut()
{

}

// evaluate : RGB with synchros
void VideoOut::eval_RGB_HV
(
    // Clock
    vluint8_t  clk,
    // Synchros
    vluint8_t  vs,
    vluint8_t  hs,
    // RGB colors
    vluint8_t  red,
    vluint8_t  green,
    vluint8_t  blue
)
{

    // Rising edge on clock
    if (clk && !prev_clk) {
        //printf("\nh stage %d, v stage %d, hs %d (prev:%d), vs %d (prev:%d), hcount %d, vcount %d, hsync_cnt:%d, vsync_cnt:%d\n",
        //       h_sync_stage,v_sync_stage,hs,prev_hs,vs,prev_vs,hcount,vcount,h_sync_count,v_sync_count);

        // Horizontal synch update
        bool h_sync_achieved = false;
        switch (h_sync_stage)
        {
        case e_Front:
            h_sync_count ++;
            if (h_sync_count == hfporch-1) {
                h_sync_stage = e_SynchPulseUp;
                h_sync_count = 0;
            }
            break;
        case e_SynchPulseUp:
            if ((hs == hs_pol) && (prev_hs != hs_pol)) {
                // raising edge on hs
                h_sync_stage = e_SynchPulseDown;
                if (dbg_on) printf(" Rising edge on HS");
            }
            break;
        case e_SynchPulseDown:
            if ((hs != hs_pol) && (prev_hs != hs_pol)) {
                // falling edge on hs
                h_sync_stage = e_Back;
                h_sync_count ++;
            }
            break;
        case e_Back:
            h_sync_count ++;
            if (h_sync_count == hbporch) {
                h_sync_stage = e_Done;
                h_sync_count = 0;
                hcount = 0;
                // just achived hsynch
                h_sync_achieved = true;
                // end of frame?
                if (vcount >= ver_size) {
                    // yes, trigger vsynch
                    vcount = 0;
                    h_sync_stage = e_Front;
                }
            }
            break;
        case e_Done: break;
        }

        // Vertical synch update, if horizontal synch achieved
        if (h_sync_achieved) {

            switch (v_sync_stage)
            {
            case e_Front:
                v_sync_count ++;
                if (v_sync_count == vfporch-1) {
                    v_sync_stage = e_SynchPulseUp;
                    v_sync_count = 0;
                }
                break;
            case e_SynchPulseUp:
                if ((vs == vs_pol) && (prev_vs != vs_pol)) {
                    // raising edge on vs
                    v_sync_stage = e_SynchPulseDown;
                    if (dbg_on) printf(" Rising edge on VS");
                }
                break;
            case e_SynchPulseDown:
                if ((vs != vs_pol) && (prev_vs != vs_pol)) {
                    // falling edge on vs
                    v_sync_stage = e_Back;
                    v_sync_count ++;

                }
                break;
            case e_Back:
                v_sync_count ++;
                if (v_sync_count == vbporch) {
                    vcount = 0;
                    v_sync_stage = e_Done;
                    v_sync_count = 0;
                    {
                        char num[64];
                        snprintf(num,64, "%04d", dump_ctr);
                        std::string tmp = filename + "_" + std::string(num) + ".tga";
                        // printf(" Save snapshot in file \"%s\"\n", tmp.c_str());
                        {
                          ImageRGB img;
                          img.pixels() = pixels;
                          saveImage(tmp.c_str(),&img);                        
                        }
                        dump_ctr++;
                    }
                }
                break;
            case e_Done: break;
            }

            prev_vs = vs;

        }

        // reset horizontal synchro
        if (h_sync_stage == e_Done) {
            if (hcount >= hor_size) {
                h_sync_stage = e_Front;
                vcount ++;
            }
        }
        // reset vertical synchro
        if (v_sync_stage == e_Done) {
            if (vcount >= ver_size) {
                h_sync_stage = e_Front;
                v_sync_stage = e_Front;
            }
        }

        // Grab active area
        if (v_sync_stage == e_Done && h_sync_stage == e_Done) {

            if (vcount < ver_size) {
                if (hcount < hor_size) {

                    uchar r = (red   & bit_mask) << (bit_shift);
                    uchar g = (green & bit_mask) << (bit_shift);
                    uchar b = (blue  & bit_mask) << (bit_shift);

                    if (hcount >= 0 && vcount >= 0 && hcount < pixels.xsize() && vcount < pixels.ysize()) {
                      pixels.at((int)(hcount), (int)(vcount)) = v3b(r,g,b);
                    // printf("*** [pixel write at %d,%d  R%dG%dB%d]\n",hcount,vcount,(int)r,(int)g,(int)b);
                    } else {
                      printf("*** [ERROR] out of bounds pixel write at %d,%d  R%dG%dB%d]\n",hcount,vcount,(int)r,(int)g,(int)b);
                    }
                }
            }
        }

        hcount ++;

        prev_hs = hs;

    }

    prev_clk = clk;

}

vluint16_t VideoOut::get_hcount()
{
    return hcount;
}

vluint16_t VideoOut::get_vcount()
{
    return vcount;
}

/*

    Silice FPGA language and compiler
    (c) Sylvain Lefebvre - @sylefeb

This work and all associated files are under the

     GNU AFFERO GENERAL PUBLIC LICENSE
        Version 3, 19 November 2007
        
A copy of the license full text is included in 
the distribution, please refer to it for details.

(header_1_0)
*/
// SL 2019-10-09

#include "Vtop.h"
#include <iostream>

int main(int argc,char **argv)
{

  Verilated::commandArgs(argc,argv);

  Vtop    *bare_test = new Vtop();

  char foo[1<<17]; // DEBUG FIXME: there is an access violation that makes this necessary. I have not been able to track it down so far!! Terrible.

  while (!Verilated::gotFinish()) {

    bare_test->clk = 1;

    bare_test->eval();

    bare_test->clk = 0;

    bare_test->eval();

  }

  return 0;
}

/*

    Silice FPGA language and compiler
    (c) Sylvain Lefebvre - @sylefeb

This work and all associated files are under the

     GNU AFFERO GENERAL PUBLIC LICENSE
        Version 3, 19 November 2007
        
A copy of the license full text is included in 
the distribution, please refer to it for details.

(header_1_0)
*/
// SL 2019-09-23

#include "Vtop.h"
#include <iostream>

#include "VgaChip.h"
#include "sdr_sdram.h"

unsigned int main_time = 0;
double sc_time_stamp()
{
  return main_time;
}

int main(int argc,char **argv)
{
  Verilated::commandArgs(argc,argv);
  
  Vtop    *vga_test = new Vtop();

  vga_test->clk = 0;

  // we need to step simulation until we get the parameters
  do {

    vga_test->clk = 1 - vga_test->clk;

    vga_test->eval();

  } while ((int)vga_test->video_color_depth == 0);

  VgaChip *vga_chip = new VgaChip((int)vga_test->video_color_depth);

  char foo[1<<18]; // DEBUG FIXME: there is an access violation that makes this necessary. I have not been able to track it down so far!! Terrible.
  
  vluint8_t sdram_flags = 0;
  if ((int)vga_test->sdram_word_width == 8) {
    sdram_flags |= FLAG_DATA_WIDTH_8;
  } else if ((int)vga_test->sdram_word_width == 16) {
    sdram_flags |= FLAG_DATA_WIDTH_16;
  } else if ((int)vga_test->sdram_word_width == 32) {
    sdram_flags |= FLAG_DATA_WIDTH_32;
  } else if ((int)vga_test->sdram_word_width == 64) {
    sdram_flags |= FLAG_DATA_WIDTH_64;
  }
  
  SDRAM* sdr  = new SDRAM(13 /*8192*/, 10 /*1024*/, sdram_flags, NULL); 
                                                              // "sdram.txt");
  vluint64_t sdram_dq = 0;
  
  vluint8_t prev_vga_vs = 0;
  
  while (!Verilated::gotFinish()) {

    vga_test->clk = 1 - vga_test->clk;

    vga_test->eval();

    sdr->eval(main_time,
              vga_test->sdram_clock, 1,
              vga_test->sdram_cs,  vga_test->sdram_ras, vga_test->sdram_cas, vga_test->sdram_we,
              vga_test->sdram_ba,  vga_test->sdram_a,
              vga_test->sdram_dqm, (vluint64_t)vga_test->sdram_dq_o, sdram_dq);

    vga_test->sdram_dq_i = (vga_test->sdram_dq_en) ? vga_test->sdram_dq_o : sdram_dq;

    if (prev_vga_vs == 0 && vga_test->video_vs != 0) {
      static int cnt = 0;
      char str[256];
      snprintf(str,256,"dump_%04d.raw",cnt++);
      sdr->save(str,4*8192*1024*2,0);
    }
    prev_vga_vs = vga_test->video_vs;
    
    vga_chip->eval(
       vga_test->video_clock,
       vga_test->video_vs,vga_test->video_hs,
       vga_test->video_r,vga_test->video_g,vga_test->video_b);

    main_time ++;
  }

  return 0;
}

// Copyright 2013 Frederic Requin
//
// This file is part of the MCC216 project (www.arcaderetrogaming.com)
//
// The SDRAM C++ model is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// The SDRAM C++ model is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// SDRAM C++ model:
// ----------------
//  - Based on the verilog model from Micron : "mt48lc8m16a2.v" // 2 meg x 16 x 4 banks
//  - Designed to work with "Verilator" tool (www.veripool.org)
//  - 8/16/32-bit data bus supported
//  - 4 banks only
//  - Two memory layouts : interleaved banks or contiguous banks
//  - Sequential burst only, no interleaved burst yet
//  - Binary images can be loaded to and saved from SDRAM
//  - Debug mode to trace every SDRAM access
//  - Endianness support for 16 and 32-bit memories
//
// TODO:
//  - Add interleaved burst support
//
// 2020-03-03 - included in silice project, Sylvain Lefebvre, @sylefeb

#ifndef _SDR_SDRAM_H_
#define _SDR_SDRAM_H_

#include "verilated.h"

#define SDRAM_NUM_BANKS        (4)
#define SDRAM_BIT_BANKS        (2)
#define CMD_PIPE_DEPTH         (4)
#define DQM_PIPE_DEPTH         (2)

#define FLAG_DATA_WIDTH_8      ((vluint8_t)0x00)
#define FLAG_DATA_WIDTH_16     ((vluint8_t)0x01)
#define FLAG_DATA_WIDTH_32     ((vluint8_t)0x03)
#define FLAG_DATA_WIDTH_64     ((vluint8_t)0x07)
#define FLAG_BANK_INTERLEAVING ((vluint8_t)0x08)
#define FLAG_BIG_ENDIAN        ((vluint8_t)0x10)
#define FLAG_RANDOM_FILLED     ((vluint8_t)0x20)
#define FLAG_DEBUG_ON          ((vluint8_t)0x40)

class SDRAM
{
    public:
        // Constructor and destructor
        SDRAM(vluint8_t log2_rows, vluint8_t log2_cols, vluint8_t flags, char *logfile);
        ~SDRAM();
        // Methods
        void load(const char *name, vluint32_t size,  vluint32_t addr);
        void save(const char *name, vluint32_t size,  vluint32_t addr);
        void eval(vluint64_t ts,    vluint8_t clk,    vluint8_t  cke,
                  vluint8_t  cs_n,  vluint8_t ras_n,  vluint8_t  cas_n, vluint8_t we_n,
                  vluint8_t  ba,    vluint16_t addr,
                  vluint8_t  dqm,   vluint64_t dq_in, vluint64_t &dq_out);
        vluint8_t  read_byte(vluint32_t addr);
        vluint16_t read_word(vluint32_t addr);
        vluint32_t read_long(vluint32_t addr);
        vluint64_t read_quad(vluint32_t addr);
        vluint32_t mem_size;
    private:
        // Byte reading functions (to speedup access)
        vluint8_t  (SDRAM::*read_byte_priv)(vluint32_t);
        vluint8_t  read_byte_i_be_8(vluint32_t addr);
        vluint8_t  read_byte_i_be_16(vluint32_t addr);
        vluint8_t  read_byte_i_be_32(vluint32_t addr);
        vluint8_t  read_byte_i_be_64(vluint32_t addr);
        vluint8_t  read_byte_i_le_8(vluint32_t addr);
        vluint8_t  read_byte_i_le_16(vluint32_t addr);
        vluint8_t  read_byte_i_le_32(vluint32_t addr);
        vluint8_t  read_byte_i_le_64(vluint32_t addr);
        vluint8_t  read_byte_c_be_8(vluint32_t addr);
        vluint8_t  read_byte_c_be_16(vluint32_t addr);
        vluint8_t  read_byte_c_be_32(vluint32_t addr);
        vluint8_t  read_byte_c_be_64(vluint32_t addr);
        vluint8_t  read_byte_c_le_8(vluint32_t addr);
        vluint8_t  read_byte_c_le_16(vluint32_t addr);
        vluint8_t  read_byte_c_le_32(vluint32_t addr);
        vluint8_t  read_byte_c_le_64(vluint32_t addr);
        // SDRAM capacity
        int        bus_mask;                     // Data bus width (bytes - 1)
        int        bus_log2;                     // Data bus width (log2(bytes))
        int        num_rows;                     // Number of rows
        int        num_cols;                     // Number of columns
        int        bit_rows;                     // Number of rows (log 2)
        int        bit_cols;                     // Number of columns (log 2)
        vluint32_t mask_bank;                    // Bit mask for banks
        vluint32_t mask_rows;                    // Bit mask for rows
        vluint32_t mask_cols;                    // Bit mask for columns
        // Memory arrays
        vluint8_t *mem_array_7[SDRAM_NUM_BANKS]; // MSB
        vluint8_t *mem_array_6[SDRAM_NUM_BANKS];
        vluint8_t *mem_array_5[SDRAM_NUM_BANKS];
        vluint8_t *mem_array_4[SDRAM_NUM_BANKS];
        vluint8_t *mem_array_3[SDRAM_NUM_BANKS];
        vluint8_t *mem_array_2[SDRAM_NUM_BANKS];
        vluint8_t *mem_array_1[SDRAM_NUM_BANKS];
        vluint8_t *mem_array_0[SDRAM_NUM_BANKS]; // LSB
        // Mode register                         
        int        cas_lat;                      // CAS latency (2 or 3)
        int        bst_len_rd;                   // Burst length during read
        int        bst_len_wr;                   // Burst length during write
        vluint8_t  bst_type;                     // Burst type
        // Debug mode                            
        vluint8_t  dbg_on;                       
        // Special memory flags                  
        vluint8_t  mem_flags;                    
        // Internal variables                    
        vluint8_t  prev_clk;                     // Previous clock state
        vluint8_t  cmd_pipe[CMD_PIPE_DEPTH];     // Command pipeline
        int        col_pipe[CMD_PIPE_DEPTH];     // Column address pipeline
        vluint8_t  ba_pipe[CMD_PIPE_DEPTH];      // Bank address pipeline
        vluint8_t  bap_pipe[CMD_PIPE_DEPTH];     // Bank precharge pipeline
        vluint8_t  a10_pipe[CMD_PIPE_DEPTH];     // A[10] wire pipeline
        vluint8_t  dqm_pipe[DQM_PIPE_DEPTH];     // DQM pipeline (for read)
        vluint8_t  row_act[SDRAM_NUM_BANKS];     // Bank activate
        vluint8_t  row_pre[SDRAM_NUM_BANKS];     // Bank precharge
        int        row_addr[SDRAM_NUM_BANKS];    // Row address during activate
        vluint8_t  ap_bank[SDRAM_NUM_BANKS];     // Bank being auto-precharged
        int        bank;                         // Current bank during read/write
        int        row;                          // Current row during read/write
        int        col;                          // Current column during read/write
        int        bst_ctr_rd;                   // Burst counter (read)
        int        bst_ctr_wr;                   // Burst counter (write)
public:
        // Log file
        FILE      *fh_log;
        char      *log_buf;
        int        log_size;
};

#endif /* _SDR_SDRAM_H_ */
// Copyright 2013 Frederic Requin
//
// This file is part of the MCC216 project (www.arcaderetrogaming.com)
//
// The SDRAM C++ model is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// The SDRAM C++ model is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// SDRAM C++ model:
// ----------------
//  - Based on the verilog model from Micron : "mt48lc8m16a2.v"
//  - Designed to work with "Verilator" tool (www.veripool.org)
//  - 8/16/32-bit data bus supported
//  - 4 banks only
//  - Two memory layouts : interleaved banks or contiguous banks
//  - Sequential burst only, no interleaved burst yet
//  - Binary images can be loaded to and saved from SDRAM
//  - Debug mode to trace every SDRAM access
//  - Endianness support for 16 and 32-bit memories
//
// TODO:
//  - Add interleaved burst support

#include "verilated.h"
#include "sdr_sdram.h"
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include <iostream>

// SDRAM commands
#define CMD_LMR  ((vluint8_t)0)
#define CMD_REF  ((vluint8_t)1)
#define CMD_PRE  ((vluint8_t)2)
#define CMD_ACT  ((vluint8_t)3)
#define CMD_WR   ((vluint8_t)4)
#define CMD_RD   ((vluint8_t)5)
#define CMD_BST  ((vluint8_t)6)
#define CMD_NOP  ((vluint8_t)7)

// Data lanes
#define DATA_MSB ((vluint8_t)0x01)
#define DATA_MSW ((vluint8_t)0x02)
#define DATA_MSL ((vluint8_t)0x04)

// Constructor
SDRAM::SDRAM(vluint8_t log2_rows, vluint8_t log2_cols, vluint8_t flags, char *logfile)
{
    // memory size 
    int s       = (int)1 << (log2_rows + log2_cols);
    // SDRAM capacity initialized
    bus_mask    =  flags & (DATA_MSB | DATA_MSW | DATA_MSL);
    bus_log2    = (flags & DATA_MSB) ? 1 : 0;
    bus_log2    = (flags & DATA_MSW) ? 2 : bus_log2;
    bus_log2    = (flags & DATA_MSL) ? 3 : bus_log2;
    bit_rows    = (int)log2_rows;
    bit_cols    = (int)log2_cols;
    num_rows    = (int)1 << log2_rows;
    num_cols    = (int)1 << log2_cols;
    mask_cols   = (num_cols - 1) << bus_log2;
    if (flags & FLAG_BANK_INTERLEAVING)
    {
        // Banks are interleaved
        mask_rows = (vluint32_t)(num_rows        - 1) << (log2_cols + bus_log2 + SDRAM_BIT_BANKS);
        mask_bank = (vluint32_t)(SDRAM_NUM_BANKS - 1) << (log2_cols + bus_log2                  );
    }
    else
    {
        // Banks are contiguous
        mask_rows = (vluint32_t)(num_rows        - 1) << (log2_cols + bus_log2                  );
        mask_bank = (vluint32_t)(SDRAM_NUM_BANKS - 1) << (log2_cols + bus_log2 + SDRAM_BIT_BANKS);
    }
    mem_size    = s << (bus_log2 + SDRAM_BIT_BANKS);
    // Init message
    std::cerr << "Instantiating " << (mem_size >> 20) << " MB SDRAM : " << SDRAM_NUM_BANKS << " banks x " << num_rows << " rows x " << num_cols << " cols x " << (8 << bus_log2) << " bits" << std::endl;
    // byte reading function
    switch (flags & (DATA_MSB | DATA_MSW | DATA_MSL | FLAG_BANK_INTERLEAVING | FLAG_BIG_ENDIAN))
    {
        // Little endian, contiguous banks
        case 0x00 : read_byte_priv = &SDRAM::read_byte_c_le_8;  break;
        case 0x01 : read_byte_priv = &SDRAM::read_byte_c_le_16; break;
        case 0x02 : read_byte_priv = &SDRAM::read_byte_c_le_32; break;
        case 0x03 : read_byte_priv = &SDRAM::read_byte_c_le_32; break;
        case 0x04 : read_byte_priv = &SDRAM::read_byte_c_le_64; break;
        case 0x05 : read_byte_priv = &SDRAM::read_byte_c_le_64; break;
        case 0x06 : read_byte_priv = &SDRAM::read_byte_c_le_64; break;
        case 0x07 : read_byte_priv = &SDRAM::read_byte_c_le_64; break;
        // Little endian, interleaved banks
        case 0x08 : read_byte_priv = &SDRAM::read_byte_i_le_8;  break;
        case 0x09 : read_byte_priv = &SDRAM::read_byte_i_le_16; break;
        case 0x0A : read_byte_priv = &SDRAM::read_byte_i_le_32; break;
        case 0x0B : read_byte_priv = &SDRAM::read_byte_i_le_32; break;
        case 0x0C : read_byte_priv = &SDRAM::read_byte_i_le_64; break;
        case 0x0D : read_byte_priv = &SDRAM::read_byte_i_le_64; break;
        case 0x0E : read_byte_priv = &SDRAM::read_byte_i_le_64; break;
        case 0x0F : read_byte_priv = &SDRAM::read_byte_i_le_64; break;
        // Big endian, contiguous banks
        case 0x10 : read_byte_priv = &SDRAM::read_byte_c_be_8;  break;
        case 0x11 : read_byte_priv = &SDRAM::read_byte_c_be_16; break;
        case 0x12 : read_byte_priv = &SDRAM::read_byte_c_be_32; break;
        case 0x13 : read_byte_priv = &SDRAM::read_byte_c_be_32; break;
        case 0x14 : read_byte_priv = &SDRAM::read_byte_c_be_64; break;
        case 0x15 : read_byte_priv = &SDRAM::read_byte_c_be_64; break;
        case 0x16 : read_byte_priv = &SDRAM::read_byte_c_be_64; break;
        case 0x17 : read_byte_priv = &SDRAM::read_byte_c_be_64; break;
        // Big endian, interleaved banks
        case 0x18 : read_byte_priv = &SDRAM::read_byte_i_be_8;  break;
        case 0x19 : read_byte_priv = &SDRAM::read_byte_i_be_16; break;
        case 0x1A : read_byte_priv = &SDRAM::read_byte_i_be_32; break;
        case 0x1B : read_byte_priv = &SDRAM::read_byte_i_be_32; break;
        case 0x1C : read_byte_priv = &SDRAM::read_byte_i_be_64; break;
        case 0x1D : read_byte_priv = &SDRAM::read_byte_i_be_64; break;
        case 0x1E : read_byte_priv = &SDRAM::read_byte_i_be_64; break;
        case 0x1F : read_byte_priv = &SDRAM::read_byte_i_be_64; break;
    }
    
    // debug mode
    if (logfile)
    {
        fh_log   = fopen(logfile, "w");
        log_buf  = new char[2048];
        log_size = 0;
        if ((fh_log) && (log_buf))
        {
            printf("SDRAM log file \"%s\" created\n", logfile);
            dbg_on = 1;
        }
        else
        {
            dbg_on = 0;
        }
    }
    else
    {
        fh_log   = (FILE *)NULL;
        log_buf  = (char *)NULL;
        log_size = 0;
        dbg_on   = 0;
    }
    
    // special flags
    mem_flags   = flags;
    
    // mode register cleared
    cas_lat     = 0;
    bst_len_rd  = (int)0;
    bst_len_wr  = (int)0;
    bst_type    = (vluint8_t)0;
    
    // internal variables cleared
    prev_clk    = (vluint8_t)0;
    for (int i = 0; i < CMD_PIPE_DEPTH; i++)
    {
        cmd_pipe[i] = CMD_NOP;
        col_pipe[i] = (int)0;
        ba_pipe[i]  = (vluint8_t)0;
        bap_pipe[i] = (vluint8_t)0;
        a10_pipe[i] = (vluint16_t)0;
    }
    dqm_pipe[0] = (vluint8_t)0;
    dqm_pipe[1] = (vluint8_t)0;
    for (int i = 0; i < SDRAM_NUM_BANKS; i++)
    {
        row_act[i]  = (vluint8_t)1;
        row_pre[i]  = (vluint8_t)0;
        row_addr[i] = (int)0;
        ap_bank[i]  = (vluint8_t)0;
    }
    bank        = (int)0;
    row         = (int)0;
    col         = (int)0;
    bst_ctr_rd  = (int)0;
    bst_ctr_wr  = (int)0;

    // one array per byte lane and per bank (up to 16 arrays)
    for (int i = 0; i < SDRAM_NUM_BANKS; i++)
    {
                              mem_array_0[i] = new vluint8_t[s];
        if (flags & DATA_MSB) mem_array_1[i] = new vluint8_t[s];
        if (flags & DATA_MSW) mem_array_2[i] = new vluint8_t[s];
        if (flags & DATA_MSW) mem_array_3[i] = new vluint8_t[s];
        if (flags & DATA_MSL) mem_array_4[i] = new vluint8_t[s];
        if (flags & DATA_MSL) mem_array_5[i] = new vluint8_t[s];
        if (flags & DATA_MSL) mem_array_6[i] = new vluint8_t[s];
        if (flags & DATA_MSL) mem_array_7[i] = new vluint8_t[s];
    }
    
    if (flags & FLAG_RANDOM_FILLED)
    {
        // fill the arrays with random numbers
        srand (time (NULL));
        for (int i = 0; i < SDRAM_NUM_BANKS; i++)
        {
            for (int j = 0; j < s; j++)
            {
                                      mem_array_0[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSB) mem_array_1[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSW) mem_array_2[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSW) mem_array_3[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSL) mem_array_4[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSL) mem_array_5[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSL) mem_array_6[i][j] = (vluint8_t)rand() & 0xFF;
                if (flags & DATA_MSL) mem_array_7[i][j] = (vluint8_t)rand() & 0xFF;
            }
        }
    }
    else
    {
        // clear the arrays
        for (int i = 0; i < SDRAM_NUM_BANKS; i++)
        {
            for (int j = 0; j < s; j++)
            {
                                      mem_array_0[i][j] = (vluint8_t)0;
                if (flags & DATA_MSB) mem_array_1[i][j] = (vluint8_t)0;
                if (flags & DATA_MSW) mem_array_2[i][j] = (vluint8_t)0;
                if (flags & DATA_MSW) mem_array_3[i][j] = (vluint8_t)0;
                if (flags & DATA_MSL) mem_array_4[i][j] = (vluint8_t)0;
                if (flags & DATA_MSL) mem_array_5[i][j] = (vluint8_t)0;
                if (flags & DATA_MSL) mem_array_6[i][j] = (vluint8_t)0;
                if (flags & DATA_MSL) mem_array_7[i][j] = (vluint8_t)0;
            }
        }
    }
}

// Destructor
SDRAM::~SDRAM()
{
    // free the memory
    for (int i = 0; i < SDRAM_NUM_BANKS; i++)
    {
                                  delete[] mem_array_0[i];
        if (mem_flags & DATA_MSB) delete[] mem_array_1[i];
        if (mem_flags & DATA_MSW) delete[] mem_array_2[i];
        if (mem_flags & DATA_MSW) delete[] mem_array_3[i];
        if (mem_flags & DATA_MSL) delete[] mem_array_4[i];
        if (mem_flags & DATA_MSL) delete[] mem_array_5[i];
        if (mem_flags & DATA_MSL) delete[] mem_array_6[i];
        if (mem_flags & DATA_MSL) delete[] mem_array_7[i];
    }
}

// Binary file loading
void SDRAM::load(const char *name, vluint32_t size, vluint32_t addr)
{
    FILE *fh;
    
    fh = fopen(name, "rb");
    if (fh)
    {
        int        row_size; // Row size (num_cols * 1, 2 or 4)
        vluint8_t *row_buf;  // Row buffer
        int        row_pos;  // Row position (0 to num_rows - 1)
        int        bank_nr;  // Bank number (0 to 3)
        int        idx;      // Array index (0 to num_cols * num_rows - 1)
        
        // Row size computation based on data bus width
        row_size = (int)1 << (bit_cols + bus_log2);
        // Allocate one full row
        row_buf = new vluint8_t[row_size];
        
        // Row position
        row_pos = (int)addr >> (bit_cols + bus_log2);
        // Banks layout
        if (mem_flags & FLAG_BANK_INTERLEAVING)
        {
            // Banks are interleaved
            bank_nr = row_pos & (SDRAM_NUM_BANKS - 1);
            row_pos = row_pos >> SDRAM_BIT_BANKS;
        }
        else
        {
            // Banks are contiguous
            bank_nr = row_pos >> bit_rows;
            row_pos = row_pos & (num_rows - 1);
        }
        idx = row_pos << bit_cols;
        
        printf("Starting row : %d, starting bank : %d\n", row_pos, bank_nr);
        printf("Loading 0x%08lX bytes @ 0x%08lX from binary file \"%s\"...", size, addr, name);
        for (int i = 0; i < (int)size; i += row_size)
        {
            // Read one full row from the binary file
            fread((void *)row_buf, row_size, 1, fh);
            
            // Here, we take care of the endianness
            if (mem_flags & FLAG_BIG_ENDIAN)
            {
                // MSB first (motorola's way)
                for (int j = 0; j < row_size; )
                {
                    // Write MSL (if present)
                    if (mem_flags & DATA_MSL)
                    {
                        mem_array_7[bank_nr][idx] = row_buf[j++];
                        mem_array_6[bank_nr][idx] = row_buf[j++];
                        mem_array_5[bank_nr][idx] = row_buf[j++];
                        mem_array_4[bank_nr][idx] = row_buf[j++];
                    }
                    // Write MSW (if present)
                    if (mem_flags & DATA_MSW)
                    {
                        mem_array_3[bank_nr][idx] = row_buf[j++];
                        mem_array_2[bank_nr][idx] = row_buf[j++];
                    }
                    // Write MSB (if present)
                    if (mem_flags & DATA_MSB)
                    {
                        mem_array_1[bank_nr][idx] = row_buf[j++];
                    }
                    // Write LSB
                    mem_array_0[bank_nr][idx] = row_buf[j++];
                    // Next word
                    idx++;
                }
            }
            else
            {
                // LSB first (intel's way)
                for (int j = 0; j < row_size; )
                {
                    // Write LSB
                    mem_array_0[bank_nr][idx] = row_buf[j++];
                    // Write MSB (if present)
                    if (mem_flags & DATA_MSB)
                    {
                        mem_array_1[bank_nr][idx] = row_buf[j++];
                    }
                    // Write MSW (if present)
                    if (mem_flags & DATA_MSW)
                    {
                        mem_array_2[bank_nr][idx] = row_buf[j++];
                        mem_array_3[bank_nr][idx] = row_buf[j++];
                    }
                    // Write MSL (if present)
                    if (mem_flags & DATA_MSL)
                    {
                        mem_array_4[bank_nr][idx] = row_buf[j++];
                        mem_array_5[bank_nr][idx] = row_buf[j++];
                        mem_array_6[bank_nr][idx] = row_buf[j++];
                        mem_array_7[bank_nr][idx] = row_buf[j++];
                    }
                    // Next word
                    idx++;
                }
            }
            
            // Compute next row's address
            if (mem_flags & FLAG_BANK_INTERLEAVING)
            {
                // Increment bank number
                bank_nr = (bank_nr + 1) & (SDRAM_NUM_BANKS - 1);
                
                // Bank #3 -> bank #0
                if (!bank_nr)
                {
                    row_pos ++;
                    if ((row_pos == (int)num_rows) && ((i + row_size) < (int)size))
                    {
                        printf("Memory overflow while loading !!\n");
                        return;
                    }
                }
                else
                {
                    idx -= (int)num_cols;
                }
            }
            else
            {
                // Increment row position
                row_pos = (row_pos + 1) & ((int)num_rows - 1);
                
                // Last row in a bank
                if (!row_pos)
                {
                    idx = 0;
                    bank_nr++;
                    if ((bank_nr == SDRAM_NUM_BANKS) && ((i + row_size) < (int)size))
                    {
                        printf("Memory overflow while loading !!\n");
                        return;
                    }
                }
            }
        }
        printf("OK\n");
        
        delete[] row_buf;
    }
    else
    {
        printf("Cannot load binary file \"%s\" !!\n", name);
    }
}

// Binary file saving
void SDRAM::save(const char *name, vluint32_t size, vluint32_t addr)
{
    FILE *fh;
    
    fh = fopen(name, "wb");
    if (fh)
    {
        int        row_size; // Row size (num_cols * 1, 2 or 4)
        vluint8_t *row_buf;  // Row buffer
        int        row_pos;  // Row position (0 to num_rows - 1)
        int        bank_nr;  // Bank number (0 to 3)
        int        idx;      // Array index (0 to num_cols * num_rows - 1)
        
        // Row size computation based on data bus width
        row_size = (int)1 << (bit_cols + bus_log2);
        // Allocate one full row
        row_buf = new vluint8_t[row_size];
        
        // Row position
        row_pos = (int)addr >> (bus_log2 + bit_cols);
        // Banks layout
        if (mem_flags & FLAG_BANK_INTERLEAVING)
        {
            // Banks are interleaved
            bank_nr = row_pos & (SDRAM_NUM_BANKS - 1);
            row_pos = row_pos >> SDRAM_BIT_BANKS;
        }
        else
        {
            // Banks are contiguous
            bank_nr = row_pos >> bit_rows;
            row_pos = row_pos & (num_rows - 1);
        }
        idx = row_pos << bit_cols;
        
        printf("Saving 0x%08lX bytes @ 0x%08lX to binary file \"%s\"...", size, addr, name);
        for (int i = 0; i < (int)size; i += row_size)
        {
            // Here, we take care of the endianness
            if (mem_flags & FLAG_BIG_ENDIAN)
            {
                // MSB first (motorola's way)
                for (int j = 0; j < row_size; )
                {
                    // Read MSL (if present)
                    if (mem_flags & DATA_MSL)
                    {
                        row_buf[j++] = mem_array_7[bank_nr][idx];
                        row_buf[j++] = mem_array_6[bank_nr][idx];
                        row_buf[j++] = mem_array_5[bank_nr][idx];
                        row_buf[j++] = mem_array_4[bank_nr][idx];
                    }
                    // Read MSW (if present)
                    if (mem_flags & DATA_MSW)
                    {
                        row_buf[j++] = mem_array_3[bank_nr][idx];
                        row_buf[j++] = mem_array_2[bank_nr][idx];
                    }
                    // Read MSB (if present)
                    if (mem_flags & DATA_MSB)
                    {
                        row_buf[j++] = mem_array_1[bank_nr][idx];
                    }
                    // Read LSB
                    row_buf[j++] = mem_array_0[bank_nr][idx];
                    // Next word
                    idx++;
                }
            }
            else
            {
                // LSB first (intel's way)
                for (int j = 0; j < row_size; )
                {
                    // Read LSB
                    row_buf[j++] = mem_array_0[bank_nr][idx];
                    // Read MSB (if present)
                    if (mem_flags & DATA_MSB)
                    {
                        row_buf[j++] = mem_array_1[bank_nr][idx];
                    }
                    // Read MSW (if present)
                    if (mem_flags & DATA_MSW)
                    {
                        row_buf[j++] = mem_array_2[bank_nr][idx];
                        row_buf[j++] = mem_array_3[bank_nr][idx];
                    }
                    // Read MSL (if present)
                    if (mem_flags & DATA_MSL)
                    {
                        row_buf[j++] = mem_array_4[bank_nr][idx];
                        row_buf[j++] = mem_array_5[bank_nr][idx];
                        row_buf[j++] = mem_array_6[bank_nr][idx];
                        row_buf[j++] = mem_array_7[bank_nr][idx];
                    }
                    // Next word
                    idx++;
                }
            }
            
            // Compute next row's address
            if (mem_flags & FLAG_BANK_INTERLEAVING)
            {
                // Increment bank number
                bank_nr = (bank_nr + 1) & (SDRAM_NUM_BANKS - 1);
                
                // Bank #3 -> bank #0
                if (!bank_nr)
                {
                    row_pos ++;
                    if ((row_pos == (int)num_rows) && ((i + row_size) < (int)size))
                    {
                        printf("Memory overflow while saving !!\n");
                        return;
                    }
                }
                else
                {
                    idx -= (int)num_cols;
                }
            }
            else
            {
                // Increment row position
                row_pos = (row_pos + 1) & ((int)num_rows - 1);
                
                // Last row in a bank
                if (!row_pos)
                {
                    idx = 0;
                    bank_nr++;
                    if ((bank_nr == SDRAM_NUM_BANKS) && ((i + row_size) < (int)size))
                    {
                        printf("Memory overflow while saving !!\n");
                        return;
                    }
                }
            }
            
            // Write one full row to the binary file
            fwrite((void *)row_buf, row_size, 1, fh);
        }
        printf("OK\n");
        
        delete[] row_buf;
        fclose(fh);
    }
    else
    {
        printf("Cannot save binary file \"%s\" !!\n", name);
    }
}

// Read a byte
vluint8_t SDRAM::read_byte(vluint32_t addr)
{
    return (this->*read_byte_priv)(addr);
}

// Read a word
vluint16_t SDRAM::read_word(vluint32_t addr)
{
    if (mem_flags & FLAG_BIG_ENDIAN)
    {
        return ((vluint16_t)(this->*read_byte_priv)(addr    ) << 8) |
                (vluint16_t)(this->*read_byte_priv)(addr + 1);
    }
    else
    {
        return ((vluint16_t)(this->*read_byte_priv)(addr + 1) << 8) |
                (vluint16_t)(this->*read_byte_priv)(addr    );
    }
}

// Read a long
vluint32_t SDRAM::read_long(vluint32_t addr)
{
    if (mem_flags & FLAG_BIG_ENDIAN)
    {
        return ((vluint32_t)(this->*read_byte_priv)(addr    ) << 24) |
               ((vluint32_t)(this->*read_byte_priv)(addr + 1) << 16) |
               ((vluint32_t)(this->*read_byte_priv)(addr + 2) <<  8) |
                (vluint32_t)(this->*read_byte_priv)(addr + 3);
    }
    else
    {
        return ((vluint32_t)(this->*read_byte_priv)(addr + 3) << 24) |
               ((vluint32_t)(this->*read_byte_priv)(addr + 2) << 16) |
               ((vluint32_t)(this->*read_byte_priv)(addr + 1) <<  8) |
                (vluint32_t)(this->*read_byte_priv)(addr    );
    }
}

// Read a quad
vluint64_t SDRAM::read_quad(vluint32_t addr)
{
    if (mem_flags & FLAG_BIG_ENDIAN)
    {
        return ((vluint64_t)(this->*read_byte_priv)(addr    ) << 56) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 1) << 48) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 1) << 40) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 1) << 32) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 1) << 24) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 1) << 16) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 2) <<  8) |
                (vluint64_t)(this->*read_byte_priv)(addr + 3);
    }
    else
    {
        return ((vluint64_t)(this->*read_byte_priv)(addr + 3) << 56) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 2) << 48) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 2) << 40) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 2) << 32) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 2) << 24) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 2) << 16) |
               ((vluint64_t)(this->*read_byte_priv)(addr + 1) <<  8) |
                (vluint64_t)(this->*read_byte_priv)(addr    );
    }
}

// Cycle evaluate
void SDRAM::eval
(
    vluint64_t ts,
    // Clock
    vluint8_t clk,
    vluint8_t cke,
    // Commands
    vluint8_t cs_n,
    vluint8_t ras_n,
    vluint8_t cas_n,
    vluint8_t we_n,
    // Address
    vluint8_t ba,
    vluint16_t addr,
    // Data
    vluint8_t dqm,
    vluint64_t dq_in,
    vluint64_t &dq_out
)
{
    // Clock enabled
    if (cke)
    {
        // Rising edge on clock
        if (clk && !(prev_clk))
        {
            vluint8_t  cmd;
            vluint8_t  a10;

            // Decode SDRAM command            
            if (!cs_n)
                cmd = (ras_n << 2) | (cas_n << 1) | we_n;
            else
                cmd = CMD_NOP;
                
            // A[10] wire
            a10 = (vluint8_t)((addr >> 10) & 1);
            // Mask out extra bits
            ba &= (SDRAM_NUM_BANKS - 1);

            // Command pipeline
            for (int i = 0; i < CMD_PIPE_DEPTH; i++)
            {
                if (i == (CMD_PIPE_DEPTH - 1))
                {
                    cmd_pipe[i] = CMD_NOP;
                    col_pipe[i] = (int)0;
                    ba_pipe[i]  = (vluint8_t)0;
                    bap_pipe[i] = (vluint8_t)0;
                    a10_pipe[i] = (vluint16_t)0;
                }
                else
                {
                    cmd_pipe[i] = cmd_pipe[i+1];
                    col_pipe[i] = col_pipe[i+1];
                    ba_pipe[i]  = ba_pipe[i+1];
                    bap_pipe[i] = bap_pipe[i+1];
                    a10_pipe[i] = a10_pipe[i+1];
                }
            }

            // DQM pipeline
            dqm_pipe[0] = dqm_pipe[1];
            dqm_pipe[1] = dqm;
            
            // Process SDRAM command (immediate)
            switch (cmd)
            {
                // 000 : Load mode register
                case CMD_LMR:
                {
                    if (dbg_on)
                    {
                        printf("Load Std Mode Register @ %llu ps\n", ts);
                        log_size += sprintf(log_buf + log_size, "Load Std Mode Register @ %llu ps\n", ts);
                    }
                        
                    // CAS latency
                    switch((addr >> 4) & 7)
                    {
                        case 2:
                        {
                            if (dbg_on)
                            {
                                printf("CAS latency        = 2 cycles\n");
                                log_size += sprintf(log_buf + log_size, "CAS latency        = 2 cycles\n");
                            }
                            cas_lat = (int)2;
                            break;
                        }
                        case 3:
                        {
                            if (dbg_on)
                            {
                                printf("CAS latency        = 3 cycles\n");
                                log_size += sprintf(log_buf + log_size, "CAS latency        = 3 cycles\n");
                            }
                            cas_lat = (int)3;
                            break;
                        }
                        default:
                        {
                            if (dbg_on)
                            {
                                printf("CAS latency        = ???\n");
                                log_size += sprintf(log_buf + log_size, "CAS latency        = ???\n");
                            }
                            cas_lat = (int)0; // This disables pipelined commands
                        }
                    }
                    
                    // Burst length
                    switch (addr & 7)
                    {
                        case 0:
                        {
                            if (dbg_on)
                            {
                                printf("Read burst length  = 1 word\n");
                                log_size += sprintf(log_buf + log_size, "Read burst length  = 1 word\n");
                            }
                            bst_len_rd = (int)1;
                            break;
                        }
                        case 1:
                        {
                            if (dbg_on)
                            {
                                printf("Read burst length  = 2 words\n");
                                log_size += sprintf(log_buf + log_size, "Read burst length  = 2 words\n");
                            }
                            bst_len_rd = (int)2;
                            break;
                        }
                        case 2:
                        {
                            if (dbg_on)
                            {
                                printf("Read burst length  = 4 words\n");
                                log_size += sprintf(log_buf + log_size, "Read burst length  = 4 words\n");
                            }
                            bst_len_rd = (int)4;
                            break;
                        }
                        case 3:
                        {
                            if (dbg_on)
                            {
                                printf("Read burst length  = 8 words\n");
                                log_size += sprintf(log_buf + log_size, "Read burst length  = 8 words\n");
                            }
                            bst_len_rd = (int)8;
                            break;
                        }
                        case 7:
                        {
                            if (dbg_on)
                            {
                                printf("Read burst length  = continuous\n");
                                log_size += sprintf(log_buf + log_size, "Read burst length  = continuous\n");
                            }
                            bst_len_rd = (int)num_cols;
                            break;
                        }
                        default:
                        {
                            if (dbg_on)
                            {
                                printf("Read burst length  = ???\n");
                                log_size += sprintf(log_buf + log_size, "Read burst length  = ???\n");
                            }
                            bst_len_rd = (int)0; // This will disable burst read
                        }
                    }
                    
                    // Burst type
                    if (addr & 8)
                    {
                        if (dbg_on)
                        {
                            printf("Burst type         = interleaved (NOT SUPPORTED !)\n");
                            log_size += sprintf(log_buf + log_size, "Burst type         = interleaved (NOT SUPPORTED !)\n");
                        }
                        bst_type = (vluint8_t)1;
                    }
                    else
                    {
                        if (dbg_on)
                        {
                            printf("Burst type         = sequential\n");
                            log_size += sprintf(log_buf + log_size, "Burst type         = sequential\n");
                        }
                        bst_type = (vluint8_t)0;
                    }
                    
                    // Write burst
                    if (addr & 0x200)
                    {
                        if (dbg_on)
                        {
                            printf("Write burst length = 1\n");
                            log_size += sprintf(log_buf + log_size, "Write burst length = 1\n");
                        }
                        bst_len_wr = (int)1;
                    }
                    else
                    {
                        if (dbg_on)
                        {
                            if (bst_len_rd)
                            {
                                if (bst_len_rd <= (int)8)
                                {
                                    printf("Write burst length = %d word(s)\n", bst_len_rd);
                                    log_size += sprintf(log_buf + log_size, "Write burst length = %d word(s)\n", bst_len_rd);
                                }
                                else
                                {
                                    printf("Write burst length = continuous\n");
                                    log_size += sprintf(log_buf + log_size, "Write burst length = continuous\n");
                                }
                            }
                            else
                            {
                                // This disables burst write
                                printf("Write burst length = ???\n");
                                log_size += sprintf(log_buf + log_size, "Write burst length = ???\n");
                            }
                        }
                        bst_len_wr = bst_len_rd;
                    }
                    break;
                }
                // 001 : Auto refresh
                case CMD_REF:
                {
                    if (dbg_on)
                        log_size += sprintf(log_buf + log_size, "Auto Refresh @ %llu ps\n", ts);
                    
                    for (int i = 0; i < SDRAM_NUM_BANKS; i++)
                    {
                        if (!row_pre[i])
                        {
                            printf("ERROR @ %llu ps : All banks must be Precharge before Auto Refresh\n", ts);
                            break;
                        }
                    }
                    break;
                }
                // 010 : Precharge
                case CMD_PRE:
                {
                    if (a10)
                    {
                        if (dbg_on)
                            log_size += sprintf(log_buf + log_size, "Precharge all banks @ %llu ps\n", ts);
                        
                        if (ap_bank[0] || ap_bank[1] || ap_bank[2] || ap_bank[3])
                        {
                            printf("ERROR @ %llu ps : at least one bank is auto-precharged !\n", ts);
                            break;
                        }
                        
                        // Precharge all banks
                        for (int i = 0; i < SDRAM_NUM_BANKS; i++)
                        {
                            row_act[i] = 0;
                            row_pre[i] = 1;
                        }
                    }
                    else
                    {
                        if (dbg_on)
                            log_size += sprintf(log_buf + log_size, "Precharge bank #%d @ %llu ps\n", ba, ts);
                            
                        if (ap_bank[ba])
                        {
                            printf("ERROR @ %llu ps : cannot apply a precharge to auto-precharged bank %d !\n", ts, ba);
                            break;
                        }
                        
                        // Precharge one bank
                        row_act[ba] = 0;
                        row_pre[ba] = 1;
                    }
                    
                    // Terminate a WRITE immediately
                    if ((a10) || (bank == (int)ba))
                        bst_ctr_wr = 0;
                    
                    // CAS latency pipeline for READ
                    if (cas_lat)
                    {
                        cmd_pipe[cas_lat] = CMD_PRE;
                        bap_pipe[cas_lat] = ba;
                        a10_pipe[cas_lat] = a10;
                    }
                    
                    break;
                }
                // 011 : Activate
                case CMD_ACT:
                {
                    // Mask out extra bits
                    addr &= (num_rows - 1);
                    
                    if (dbg_on)
                        log_size += sprintf(log_buf + log_size, "Activate bank #%d, row #%d @ %llu ps\n", ba, addr, ts);
                            
                    if (row_act[ba])
                    {
                        printf("ERROR @ %llu ps : bank %d already active !\n", ts, ba);
                        break;
                    }
                       
                    row_act[ba]  = 1;
                    row_pre[ba]  = 0;
                    row_addr[ba] = (int)addr << bit_cols;
                    
                    break;
                }
                // 100 : Write
                case CMD_WR:
                {
                    // Mask out extra bits
                    addr &= (mask_cols >> bus_log2);
                    
                    if (dbg_on)
                        log_size += sprintf(log_buf + log_size, "Write bank #%d, col #%d @ %llu ps\n", ba, addr, ts);
                    
                    if (!row_act[ba])
                    {
                        printf("ERROR @ %llu ps : bank %d is not activated for WRITE !\n", ts, ba);
                        break;
                    }
                       
                    // Latch command right away
                    cmd_pipe[0] = CMD_WR;
                    col_pipe[0] = (int)addr;
                    ba_pipe[0]  = ba;

                    // Auto-precharge
                    ap_bank[ba] = a10;
                    
                    break;
                }
                // 101 : Read
                case CMD_RD:
                {
                    // Mask out extra bits
                    addr &= (mask_cols >> bus_log2);
                    
                    if (dbg_on)
                        log_size += sprintf(log_buf + log_size, "Read bank #%d, col #%d @ %llu ps\n", ba, addr, ts);
                    
                    if (!row_act[ba])
                    {
                        printf("ERROR @ %llu ps : bank %d is not activated for READ !\n", ts, ba);
                        break;
                    }
                       
                    // CAS latency pipeline
                    if (cas_lat)
                    {
                        cmd_pipe[cas_lat] = CMD_RD;
                        col_pipe[cas_lat] = (int)addr;
                        ba_pipe[cas_lat]  = ba;
                    }
                    
                    // Auto-precharge
                    ap_bank[ba] = a10;
                    
                    break;
                }
                // 110 : Burst stop
                case CMD_BST:
                {
                    if (dbg_on)
                        log_size += sprintf(log_buf + log_size, "Burst Stop bank #%d @ %llu ps\n", ba, ts);
                        
                    if (ap_bank[ba])
                    {
                        printf("ERROR @ %llu ps : cannot apply a burst stop to auto-precharged bank %d !\n", ts, ba);
                        break;
                    }
                        
                    // Terminate a WRITE immediately
                    bst_ctr_wr = (vluint16_t)0;
                    
                    // CAS latency for READ
                    if (cas_lat)
                    {
                        cmd_pipe[cas_lat] = CMD_BST;
                    }
                    break;
                }
                // 111 : No operation
                default: ;
            }
            
            // Process SDRAM command (pipelined)
            switch (cmd_pipe[0])
            {
                // 010 : Precharge
                case CMD_PRE:
                {
                    if ((a10_pipe[0]) || (bap_pipe[0] == (vluint8_t)bank))
                        bst_ctr_rd = (int)0;
                    break;
                }
                // 100 : Write
                case CMD_WR:
                {
                    // Bank, row and column addresses in memory array
                    bank       = (int)ba_pipe[0];
                    row        = row_addr[bank] + (col_pipe[0] & ~(bst_len_wr - 1));
                    col        = col_pipe[0] & (bst_len_wr - 1);
                    bst_ctr_rd = (int)0;
                    bst_ctr_wr = bst_len_wr;
                    
                    if (dbg_on)
                    {
                        if (mem_flags & FLAG_BANK_INTERLEAVING)
                            fprintf(fh_log, "%08X : ", ((row_addr[bank] << SDRAM_BIT_BANKS) + (bank << bit_cols) + col_pipe[0]) << bus_log2);
                        else
                            fprintf(fh_log, "%08X : ", (row_addr[bank] + (bank << (bit_rows + bit_cols)) + col_pipe[0]) << bus_log2);
                    }
                    
                    break;
                }
                // 101 : Read
                case CMD_RD:
                {
                    if (dbg_on)
                    {
                        if (bst_ctr_rd) fprintf(fh_log, "\n");
                        if (log_size) fprintf(fh_log, log_buf);
                        log_size = 0;
                    }
                        
                    // Bank, row and column addresses in memory array
                    bank       = (int)ba_pipe[0];
                    row        = row_addr[bank] + (col_pipe[0] & ~(bst_len_rd - 1));
                    col        = col_pipe[0] & (bst_len_rd - 1);
                    bst_ctr_rd = bst_len_rd;
                    bst_ctr_wr = (int)0;
                    
                    if (dbg_on)
                    {
                        if (mem_flags & FLAG_BANK_INTERLEAVING)
                            fprintf(fh_log, "%08X : ", ((row_addr[bank] << SDRAM_BIT_BANKS) + (bank << bit_cols) + col_pipe[0]) << bus_log2);
                        else
                            fprintf(fh_log, "%08X : ", (row_addr[bank] + (bank << (bit_rows + bit_cols)) + col_pipe[0]) << bus_log2);
                    }
                    
                    break;
                }
                // 110 : Burst stop
                case CMD_BST:
                {
                    bst_ctr_rd = (int)0;
                    break;
                }
                // 111 : No operation
                default: ;
            }
            
            // Write to memory
            if (bst_ctr_wr)
            {
                // Write MSL (if present)
                if (mem_flags & DATA_MSL)
                {
                    if (dqm & 0x80)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_7[bank][row + col] = (vluint8_t)(dq_in >> 56);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_7[bank][row + col]);
                    }
                    if (dqm & 0x40)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_6[bank][row + col] = (vluint8_t)(dq_in >> 48);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_6[bank][row + col]);
                    }
                    if (dqm & 0x20)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_5[bank][row + col] = (vluint8_t)(dq_in >> 40);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_5[bank][row + col]);
                    }
                    if (dqm & 0x10)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_4[bank][row + col] = (vluint8_t)(dq_in >> 32);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_4[bank][row + col]);
                    }
                }
                // Write MSW (if present)
                if (mem_flags & DATA_MSW)
                {
                    if (dqm & 0x08)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_3[bank][row + col] = (vluint8_t)(dq_in >> 24);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_3[bank][row + col]);
                    }
                    if (dqm & 0x04)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_2[bank][row + col] = (vluint8_t)(dq_in >> 16);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_2[bank][row + col]);
                    }
                }
                // Write MSB (if present)
                if (mem_flags & DATA_MSB)
                {
                    if (dqm & 0x02)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        mem_array_1[bank][row + col] = (vluint8_t)(dq_in >> 8);
                        if (dbg_on) fprintf(fh_log, "%02X", mem_array_1[bank][row + col]);
                    }
                }
                // Write LSB
                if (dqm & 0x01)
                {
                    if (dbg_on) fprintf(fh_log, "XX ");
                }
                else
                {
                    mem_array_0[bank][row + col] = (vluint8_t)dq_in;
                    if (dbg_on) fprintf(fh_log, "%02X ", mem_array_0[bank][row + col]);
                }                    
                
                // Burst counter (only sequential burst supported)
                col = (col + 1) & (bst_len_wr - 1);
                bst_ctr_wr--;
                
                // End of burst
                if (bst_ctr_wr == (int)0)
                {
                    // Auto-precharge case
                    if (ap_bank[bank])
                    {
                        if (dbg_on) fprintf(fh_log, "PRE\n\n");
                        ap_bank[bank] = (vluint8_t)0;
                        row_act[bank] = (vluint8_t)0;
                        row_pre[bank] = (vluint8_t)1;
                    }
                    else
                    {
                        if (dbg_on) fprintf(fh_log, "\n");
                    }
                    if (log_size)
                    {
                        fprintf(fh_log, log_buf);
                        log_size = 0;
                    }
                }
            }
            
            // Read from memory
            if (bst_ctr_rd)
            {
                vluint8_t dq_tmp[8];
                
                dq_tmp[7] = (vluint8_t)0x00;
                dq_tmp[6] = (vluint8_t)0x00;
                dq_tmp[5] = (vluint8_t)0x00;
                dq_tmp[4] = (vluint8_t)0x00;
                dq_tmp[3] = (vluint8_t)0x00;
                dq_tmp[2] = (vluint8_t)0x00;
                dq_tmp[1] = (vluint8_t)0x00;
                dq_tmp[0] = (vluint8_t)0x00;
                
                // Read MSL (if present)
                if (mem_flags & DATA_MSL)
                {
                    if (dqm_pipe[0] & 0x80)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[7] = mem_array_7[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[7]);
                    }
                    if (dqm_pipe[0] & 0x40)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[6] = mem_array_6[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[6]);
                    }
                    if (dqm_pipe[0] & 0x20)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[5] = mem_array_5[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[5]);
                    }
                    if (dqm_pipe[0] & 0x10)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[4] = mem_array_4[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[4]);
                    }
                }
                
                // Read MSW (if present)
                if (mem_flags & DATA_MSW)
                {
                    if (dqm_pipe[0] & 0x08)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[3] = mem_array_3[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[3]);
                    }
                    if (dqm_pipe[0] & 0x04)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[2] = mem_array_2[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[2]);
                    }
                }
                
                // Read MSB (if present)
                if (mem_flags & DATA_MSB)
                {
                    if (dqm_pipe[0] & 0x02)
                    {
                        if (dbg_on) fprintf(fh_log, "XX");
                    }
                    else
                    {
                        dq_tmp[1] = mem_array_1[bank][row + col];
                        if (dbg_on) fprintf(fh_log, "%02X", dq_tmp[1]);
                    }
                }

                // Read LSB
                if (dqm_pipe[0] & 0x01)
                {
                    if (dbg_on) fprintf(fh_log, "XX ");
                }
                else
                {
                    dq_tmp[0] = mem_array_0[bank][row + col];
                    if (dbg_on) fprintf(fh_log, "%02X ", dq_tmp[0]);
                }
                
                dq_out = ((vluint64_t)dq_tmp[0]      )
                       | ((vluint64_t)dq_tmp[1] << 8 )
                       | ((vluint64_t)dq_tmp[2] << 16)
                       | ((vluint64_t)dq_tmp[3] << 24)
                       | ((vluint64_t)dq_tmp[4] << 32)
                       | ((vluint64_t)dq_tmp[5] << 40)
                       | ((vluint64_t)dq_tmp[6] << 48)
                       | ((vluint64_t)dq_tmp[7] << 56);
                
                // Burst counter (only sequential supported)
                col = (col + 1) & (bst_len_rd - 1);
                bst_ctr_rd--;
                
                // End of burst
                if (bst_ctr_rd == (int)0)
                {
                    // Auto-precharge case
                    if (ap_bank[bank])
                    {
                        if (dbg_on) fprintf(fh_log, "PRE\n");
                        ap_bank[bank] = (vluint8_t)0;
                        row_act[bank] = (vluint8_t)0;
                        row_pre[bank] = (vluint8_t)1;
                    }
                    else
                    {
                        if (dbg_on) fprintf(fh_log, "\n");
                    }
                    if (log_size)
                    {
                        fprintf(fh_log, log_buf);
                        log_size = 0;
                    }
                }
            }
        }
        
        if ((bst_ctr_wr == (int)0) && (bst_ctr_rd == (int)0) && (log_size != (int)0))
        {
            fprintf(fh_log, log_buf);
            log_size = 0;
        }
        
        // For edge detection
        prev_clk = clk;
    }
    // Clock disabled
    else
    {
        prev_clk = (vluint8_t)0;
    }
}

// Read a byte, interleaved banks, big endian, 8-bit SDRAM
vluint8_t SDRAM::read_byte_i_be_8(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> bit_cols;
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS));

    return mem_array_0[bank_nr][idx];
}

// Read a byte, interleaved banks, big endian, 16-bit SDRAM
vluint8_t SDRAM::read_byte_i_be_16(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + 1);
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS)) >> 1;

    if (addr & 1)
        return mem_array_0[bank_nr][idx];
    else
        return mem_array_1[bank_nr][idx];
}

// Read a byte, interleaved banks, big endian, 32-bit SDRAM
vluint8_t SDRAM::read_byte_i_be_32(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + 2);
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS)) >> 2;

    switch (addr & 3)
    {
        case 0 : return mem_array_3[bank_nr][idx];
        case 1 : return mem_array_2[bank_nr][idx];
        case 2 : return mem_array_1[bank_nr][idx];
        case 3 : return mem_array_0[bank_nr][idx];
    }
    return 0;
}

// Read a byte, interleaved banks, big endian, 64-bit SDRAM
vluint8_t SDRAM::read_byte_i_be_64(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + 3);
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS)) >> 3;

    switch (addr & 7)
    {
        case 0 : return mem_array_7[bank_nr][idx];
        case 1 : return mem_array_6[bank_nr][idx];
        case 2 : return mem_array_5[bank_nr][idx];
        case 3 : return mem_array_4[bank_nr][idx];
        case 4 : return mem_array_3[bank_nr][idx];
        case 5 : return mem_array_2[bank_nr][idx];
        case 6 : return mem_array_1[bank_nr][idx];
        case 7 : return mem_array_0[bank_nr][idx];
    }
    return 0;
}

// Read a byte, interleaved banks, little endian, 8-bit SDRAM
vluint8_t SDRAM::read_byte_i_le_8(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> bit_cols;
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS));

    return mem_array_0[bank_nr][idx];
}

// Read a byte, interleaved banks, little endian, 16-bit SDRAM
vluint8_t SDRAM::read_byte_i_le_16(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + 1);
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS)) >> 1;

    if (addr & 1)
        return mem_array_1[bank_nr][idx];
    else
        return mem_array_0[bank_nr][idx];
}

// Read a byte, interleaved banks, little endian, 32-bit SDRAM
vluint8_t SDRAM::read_byte_i_le_32(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + 2);
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS)) >> 2;

    switch (addr & 3)
    {
        case 0 : return mem_array_0[bank_nr][idx];
        case 1 : return mem_array_1[bank_nr][idx];
        case 2 : return mem_array_2[bank_nr][idx];
        case 3 : return mem_array_3[bank_nr][idx];
    }
    return 0;
}

// Read a byte, interleaved banks, little endian, 64-bit SDRAM
vluint8_t SDRAM::read_byte_i_le_64(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + 3);
    idx     = (int)((addr & mask_cols) | ((addr & mask_rows) >> SDRAM_BIT_BANKS)) >> 3;

    switch (addr & 7)
    {
        case 0 : return mem_array_0[bank_nr][idx];
        case 1 : return mem_array_1[bank_nr][idx];
        case 2 : return mem_array_2[bank_nr][idx];
        case 3 : return mem_array_3[bank_nr][idx];
        case 4 : return mem_array_4[bank_nr][idx];
        case 5 : return mem_array_5[bank_nr][idx];
        case 6 : return mem_array_6[bank_nr][idx];
        case 7 : return mem_array_7[bank_nr][idx];
    }
    return 0;
}

// Read a byte, contiguous banks, big endian, 8-bit SDRAM
vluint8_t SDRAM::read_byte_c_be_8(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows);
    idx     = (int)(addr & (mask_cols | mask_rows));

    return mem_array_0[bank_nr][idx];
}

// Read a byte, contiguous banks, big endian, 16-bit SDRAM
vluint8_t SDRAM::read_byte_c_be_16(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows + 1);
    idx     = (int)(addr & (mask_cols | mask_rows)) >> 1;

    if (addr & 1)
        return mem_array_0[bank_nr][idx];
    else
        return mem_array_1[bank_nr][idx];
}

// Read a byte, contiguous banks, big endian, 32-bit SDRAM
vluint8_t SDRAM::read_byte_c_be_32(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows + 2);
    idx     = (int)(addr & (mask_cols | mask_rows)) >> 2;

    switch (addr & 3)
    {
        case 0 : return mem_array_3[bank_nr][idx];
        case 1 : return mem_array_2[bank_nr][idx];
        case 2 : return mem_array_1[bank_nr][idx];
        case 3 : return mem_array_0[bank_nr][idx];
    }
    return 0;
}

// Read a byte, contiguous banks, big endian, 64-bit SDRAM
vluint8_t SDRAM::read_byte_c_be_64(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows + 3);
    idx     = (int)(addr & (mask_cols | mask_rows)) >> 3;

    switch (addr & 7)
    {
        case 0 : return mem_array_7[bank_nr][idx];
        case 1 : return mem_array_6[bank_nr][idx];
        case 2 : return mem_array_5[bank_nr][idx];
        case 3 : return mem_array_4[bank_nr][idx];
        case 4 : return mem_array_3[bank_nr][idx];
        case 5 : return mem_array_2[bank_nr][idx];
        case 6 : return mem_array_1[bank_nr][idx];
        case 7 : return mem_array_0[bank_nr][idx];
    }
    return 0;
}

// Read a byte, contiguous banks, little endian, 8-bit SDRAM
vluint8_t SDRAM::read_byte_c_le_8(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows);
    idx     = (int)(addr & (mask_cols | mask_rows));

    return mem_array_0[bank_nr][idx];
}

// Read a byte, contiguous banks, little endian, 16-bit SDRAM
vluint8_t SDRAM::read_byte_c_le_16(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows + 1);
    idx     = (int)(addr & (mask_cols | mask_rows)) >> 1;

    if (addr & 1)
        return mem_array_1[bank_nr][idx];
    else
        return mem_array_0[bank_nr][idx];
}

// Read a byte, contiguous banks, little endian, 32-bit SDRAM
vluint8_t SDRAM::read_byte_c_le_32(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows + 2);
    idx     = (int)(addr & (mask_cols | mask_rows)) >> 2;

    switch (addr & 3)
    {
        case 0 : return mem_array_0[bank_nr][idx];
        case 1 : return mem_array_1[bank_nr][idx];
        case 2 : return mem_array_2[bank_nr][idx];
        case 3 : return mem_array_3[bank_nr][idx];
    }
    return 0;
}

// Read a byte, contiguous banks, little endian, 64-bit SDRAM
vluint8_t SDRAM::read_byte_c_le_64(vluint32_t addr)
{
    int        bank_nr;  // Bank number (0 to 3)
    int        idx;      // Array index (0 to num_cols * num_rows - 1)
    
    bank_nr = (int)(addr & mask_bank) >> (bit_cols + bit_rows + 3);
    idx     = (int)(addr & (mask_cols | mask_rows)) >> 3;

    switch (addr & 7)
    {
        case 0 : return mem_array_0[bank_nr][idx];
        case 1 : return mem_array_1[bank_nr][idx];
        case 2 : return mem_array_2[bank_nr][idx];
        case 3 : return mem_array_3[bank_nr][idx];
        case 4 : return mem_array_4[bank_nr][idx];
        case 5 : return mem_array_5[bank_nr][idx];
        case 6 : return mem_array_6[bank_nr][idx];
        case 7 : return mem_array_7[bank_nr][idx];
    }
    return 0;
}
/*

    Silice FPGA language and compiler
    (c) Sylvain Lefebvre - @sylefeb

This work and all associated files are under the

     GNU AFFERO GENERAL PUBLIC LICENSE
        Version 3, 19 November 2007
        
A copy of the license full text is included in 
the distribution, please refer to it for details.

(header_1_0)
*/
// Sylvain Lefebvre 2019-09-26

#pragma once

#include "verilated.h"

class VideoOut;

/// \brief Isolates the implementation to simplify build
class VgaChip
{
private:

  VideoOut *m_VideoOut = nullptr;

public:

  VgaChip(int color_depth);
  ~VgaChip();
  
  void eval(vluint8_t  clk,
            vluint8_t  vs,   
            vluint8_t  hs,   
            vluint8_t  red,  
            vluint8_t  green, 
            vluint8_t  blue);
  
};

cmake_minimum_required(VERSION 2.6)
project(verilator_silice)

# find_package(verilator) ?

INCLUDE_DIRECTORIES(
  ${PROJECT_SOURCE_DIR}/
  ${PROJECT_SOURCE_DIR}/../../src/libs/LibSL-small/src
  ${PROJECT_SOURCE_DIR}/../../src/libs/LibSL-small/src/LibSL  
  $ENV{VERILATOR_ROOT}/include
)

add_definitions(-Wfatal-errors)

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# hack to deal with https://github.com/verilator/verilator/issues/2502
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()

ADD_LIBRARY(verilator_silice
  video_out.cpp
  video_out.h
  sdr_sdram.cpp
  sdr_sdram.h
  VgaChip.cpp
  VgaChip.h
  ../../src/libs/LibSL-small/src/LibSL/System/System.cpp
  ../../src/libs/LibSL-small/src/LibSL/CppHelpers/CppHelpers.cpp
  ../../src/libs/LibSL-small/src/LibSL/StlHelpers/StlHelpers.cpp
  ../../src/libs/LibSL-small/src/LibSL/Math/Math.cpp
  ../../src/libs/LibSL-small/src/LibSL/Math/Vertex.cpp
  ../../src/libs/LibSL-small/src/LibSL/Image/Image.cpp
  ../../src/libs/LibSL-small/src/LibSL/Image/ImageFormat_TGA.cpp
  ../../src/libs/LibSL-small/src/LibSL/Image/tga.cpp
)

INSTALL(TARGETS verilator_silice ARCHIVE DESTINATION ${CMAKE_SOURCE_DIR})

/*

    Silice FPGA language and compiler
    (c) Sylvain Lefebvre - @sylefeb

This work and all associated files are under the

     GNU AFFERO GENERAL PUBLIC LICENSE
        Version 3, 19 November 2007
        
A copy of the license full text is included in 
the distribution, please refer to it for details.

(header_1_0)
*/
//
// Implements VGA emulation for Verilator.
// Emulates front/back porch on horizontal and vertical synch.
//
// Based on code from the MCC216 project (https://github.com/fredrequin/fpga_1943)
// (c) Frederic Requin, GPL v3 license
//

#pragma once

#include "verilated.h"
#include "LibSL/Image/Image.h"

#define HS_POS_POL 1
#define HS_NEG_POL 0
#define VS_POS_POL 2
#define VS_NEG_POL 0

class VideoOut
{
    public:
    
        // Constructor and destructor
        VideoOut(
          vluint8_t debug, 
          vluint8_t depth, 
          vluint8_t polarity, 
          vluint16_t hactive, vluint16_t hfporch_, vluint16_t hspulse_, vluint16_t hbporch_,
          vluint16_t vactive, vluint16_t vfporch_, vluint16_t vspulse_, vluint16_t vbporch_,
          const char *file);
        ~VideoOut();
        // Methods
        void eval_RGB_HV(vluint8_t clk, vluint8_t vs,   vluint8_t hs,   vluint8_t red,  vluint8_t green, vluint8_t blue);
        vluint16_t get_hcount();
        vluint16_t get_vcount();
    private:
        // Color depth
        int        bit_shift;
        vluint8_t  bit_mask;
        // Synchros polarities
        vluint8_t  hs_pol;
        vluint8_t  vs_pol;
        // Debug mode
        vluint8_t  dbg_on;
        // H synch
        vluint16_t hfporch;
        vluint16_t hspulse; 
        vluint16_t hbporch;
        // V synch
        vluint16_t vfporch;
        vluint16_t vspulse; 
        vluint16_t vbporch;
        // Image format
        vluint16_t hor_size;
        vluint16_t ver_size;
        // Pixel array
        LibSL::Memory::Array::Array2D<LibSL::Math::v3b> pixels;
        // Image file name
        std::string filename;
        // Internal variable
        vluint16_t hcount;
        vluint16_t vcount;
        vluint8_t  prev_clk;
        vluint8_t  prev_hs;
        vluint8_t  prev_vs;
        int        dump_ctr;
        
        enum e_Synch {e_Front=0,e_SynchPulseUp=1,e_SynchPulseDown=2,e_Back=3,e_Done=4};

        e_Synch    v_sync_stage;
        e_Synch    h_sync_stage;
        int        v_sync_count;
        int        h_sync_count;
};

{
  "boards" : [
    {
      "name" : "icarus"
    },
    {
      "name" : "verilator"
    },
    {
      "name" : "icebreaker"
    },
    {
      "name" : "icestick"
    },
    {
      "name" : "ulx3s"
    },
    {
      "name" : "de10nano"
    },
    {
      "name" : "orangecrab"
    },
    {
      "name" : "crosslink_nx_evn"
    },
    {
      "name" : "fomu"
    },
    {
      "name" : "mojov3"
    },
    {
      "name" : "techgraph"
    },
    {
      "name" : "8bitworkshop"
    }
  ]
}
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build*

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

yosys -q -p "synth_ice40 -json build.json" build.v
nextpnr-ice40 --up5k --freq 13 --package sg48 --json build.json --pcf $BOARD_DIR/icebreaker.pcf --asc build.asc

icepack build.asc build.bin
iceprog build.bin
# ----------------------------------------------------------------------------
#
# Icebreaker constraint file (.pcf)
# Pinout:
# https://github.com/icebreaker-fpga/icebreaker/blob/master/img/icebreaker-v1_0b-legend.jpg
# Link
# https://1bitsquared.com/collections/fpga/products/icebreaker
#
# ----------------------------------------------------------------------------

# -------------------------- SYSTEM CLOCK ------------------------------------
set_io -nowarn CLK 35

# ------------------------------ UART ----------------------------------------
set_io -nowarn RX 6
set_io -nowarn TX 9

# ------------------------- LEDs and Button ----------------------------------
set_io -nowarn BTN_N      10
set_io -nowarn LEDR_N     11
set_io -nowarn LEDG_N     37

# --------------------------- SPI Flash --------------------------------------
set_io -nowarn FLASH_SCK  15
set_io -nowarn FLASH_SSB  16
set_io -nowarn FLASH_IO0  14
set_io -nowarn FLASH_IO1  17
set_io -nowarn FLASH_IO2  12
set_io -nowarn FLASH_IO3  13

# ------------ Leds and Buttons (PMOD 2) -------------------------------------
set_io -nowarn LED1 26
set_io -nowarn LED2 27
set_io -nowarn LED3 25
set_io -nowarn LED4 23
set_io -nowarn LED5 21
set_io -nowarn BTN1 20
set_io -nowarn BTN2 19
set_io -nowarn BTN3 18

# ------------ PMOD1A connector ----------------------------------------------
set_io -nowarn P1A1   4
set_io -nowarn P1A2   2
set_io -nowarn P1A3  47
set_io -nowarn P1A4  45
set_io -nowarn P1A7   3
set_io -nowarn P1A8  48
set_io -nowarn P1A9  46
set_io -nowarn P1A10 44

# ------------ PMOD1B connector ----------------------------------------------
set_io -nowarn P1B1  43
set_io -nowarn P1B2  38
set_io -nowarn P1B3  34
set_io -nowarn P1B4  31
set_io -nowarn P1B7  42
set_io -nowarn P1B8  36
set_io -nowarn P1B9  32
set_io -nowarn P1B10 28

# ------------ Leds and Buttons (PMOD 2) -------------------------------------
set_io -nowarn P2_1  27
set_io -nowarn P2_2  25
set_io -nowarn P2_3  21
set_io -nowarn P2_4  19
set_io -nowarn P2_7  26
set_io -nowarn P2_8  23
set_io -nowarn P2_9  20
set_io -nowarn P2_10 18
{
  "name": "icebreaker",
  "variants": [
    {
      "name"      : "configurable",
      "framework" : "icebreaker.v",
      "pins"      : [         
        {"set"    : "basic"},
        {"set"    : "buttons", "define" : "BUTTONS=1"},
        {"set"    : "uart", "define" : "UART=1"},
        {"set"    : "vga", "define" : "VGA=1"} 
      ],
      "builders": [
        {
          "builder" : "edalize",
          "description": "Build using Edalize",
          "tool": "icestorm",
          "tool_options": [
            {
                "nextpnr_options": ["--up5k", "--freq 13", "--package sg48", "--timing-allow-fail"],
                "pnr": "next"
            }
          ],
          "bitstream"  : "build.bin",
          "constraints": [{"name": "icebreaker.pcf", "file_type": "PCF"}],
          "program": [{"cmd" : "iceprog", "args" : "build.bin"}]
        },
        {
          "builder" : "shell",
          "command" : "icebreaker.sh",
          "description": "Custom shell scripts using yosys and nextpnr"
        }
      ]    
    }
  ],
  "pins": {
    "basic": [
        {
          "name": "leds",
          "type": "uint5",
          "io": "output"
        }
    ],    
    "buttons": [
      {
        "name": "btns",
        "type": "uint3",
        "io": "input"
      }
    ],
    "uart": [
      {
        "name": "uart_tx",
        "type": "uint1",
        "io"  : "output"
      },
      {
        "name": "uart_rx",
        "type": "uint1",
        "io"  : "input"
      }
    ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ]
  }
}
`define ICEBREAKER 1
`default_nettype none
$$ICEBREAKER=1
$$HARDWARE=1
$$NUM_LEDS=5
$$NUM_BTNS=3
$$VGA=1
$$color_depth=6
$$color_max  =63
$$config['bram_wenable_width'] = 'data'
$$config['dualport_bram_wenable0_width'] = 'data'
$$config['dualport_bram_wenable1_width'] = 'data'

module top(
  output LED1,
  output LED2,
  output LED3,
  output LED4,
  output LED5,
`ifdef BUTTONS
  input BTN1,
  input BTN2,
  input BTN3,
`endif
`ifdef UART
  output TX,
  input  RX,
`endif
`ifdef VGA
  output P1A1, // r0
  output P1A2, // r1
  output P1A3, // r2
  output P1A4, // r3
  
  output P1A7,   // b0
  output P1A8,   // b1
  output P1A9,   // b2
  output P1A10,  // b3
  
  output P1B1,  // g0
  output P1B2,  // g1
  output P1B3,  // g2
  output P1B4,  // g3
  
  output P1B7, // hs
  output P1B8,  // vs
`endif  
  input  CLK
  );

wire [4:0] __main_leds;

// clock from design is used in case
// it relies on a PLL: in such cases
// we cannot use the clock fed into
// the PLL here
wire design_clk;

`ifdef VGA
wire __main_out_vga_hs;
wire __main_out_vga_vs;
wire __main_out_vga_v0;
wire [5:0] __main_out_vga_r;
wire [5:0] __main_out_vga_g;
wire [5:0] __main_out_vga_b;
`endif  

reg ready = 0;
reg [31:0] RST_d;
reg [31:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge design_clk) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 32'b111111111111111111111111111111;
  end
end

wire run_main;
assign run_main = 1'b1;

M_main __main(
  .clock(CLK),
  .out_clock(design_clk),
  .reset(RST_d[0]),
  .out_leds(__main_leds),
`ifdef BUTTONS
  .in_btns({BTN3,BTN2,BTN1}),
`endif
`ifdef UART
  .out_uart_tx(TX),
  .in_uart_rx(RX),
`endif
`ifdef VGA
  .out_video_hs(__main_out_vga_hs),
  .out_video_vs(__main_out_vga_vs),
  .out_video_r(__main_out_vga_r),
  .out_video_g(__main_out_vga_g),
  .out_video_b(__main_out_vga_b),
`endif
  .in_run(run_main)
);

assign LED1 = __main_leds[0+:1];
assign LED2 = __main_leds[1+:1];
assign LED3 = __main_leds[2+:1];
assign LED4 = __main_leds[3+:1];
assign LED5 = __main_leds[4+:1];

`ifdef VGA
assign P1A1  = __main_out_vga_r[2+:1];
assign P1A2  = __main_out_vga_r[3+:1];
assign P1A3  = __main_out_vga_r[4+:1];
assign P1A4  = __main_out_vga_r[5+:1];

assign P1A7  = __main_out_vga_b[2+:1];
assign P1A8  = __main_out_vga_b[3+:1];
assign P1A9  = __main_out_vga_b[4+:1];
assign P1A10 = __main_out_vga_b[5+:1];

assign P1B1  = __main_out_vga_g[2+:1];
assign P1B2  = __main_out_vga_g[3+:1];
assign P1B3  = __main_out_vga_g[4+:1];
assign P1B4  = __main_out_vga_g[5+:1];

assign P1B7  = __main_out_vga_hs;
assign P1B8  = __main_out_vga_vs;
`endif

endmodule
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build*

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

yosys -p 'synth_ecp5 -abc9 -json build.json' build.v

nextpnr-ecp5 --25k --package CSFBGA285 --json build.json --textcfg build.config --lpf $BOARD_DIR/pinout.lpf --timing-allow-fail --freq 38.8

ecppack --freq 38.8 --compress build.config build.bit

cp build.bit build.dfu
dfu-suffix -v 1209 -p 5af0 -a build.dfu
dfu-util -D build.dfu
`define ORANGECRAB 1
`default_nettype none
$$ORANGECRAB=1
$$HARDWARE=1
$$NUM_LEDS=3

module top(
  input  CLK, // 38.8 MHz
  // bare
  output [2:0] LED
  );

// input/output wires

wire [2:0]  __main_out_leds;

assign LED  = __main_out_leds;

// reset

reg ready = 0;

reg [15:0] RST_d;
reg [15:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge CLK) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 16'b1111111111111111;
  end
end

// main

wire   run_main;
assign run_main = 1'b1;

M_main __main(
  .clock         (CLK),
  .reset         (RST_q[0]),
  .in_run        (run_main),
  .out_leds      (__main_out_leds)
);

endmodule
{
  "name": "orangecrab",
  "variants": [
    {
      "name"      : "r2_0",
      "framework" : "orangecrab.v",
      "pins"      : [ 
        {"set"    : "basic"}
      ],
      "builders": [
        {
          "builder" : "edalize",
          "description": "Build using Edalize",
          "tool": "trellis",
          "tool_options": [
            {
                "nextpnr_options": ["--25k", "--freq 38.8", "--package CSFBGA285", "--timing-allow-fail"],
                "pnr": "next"
            }
          ],
          "bitstream"  : "build.dfu",
          "constraints": [{"name": "pinout.lpf", "file_type": "LPF"}],
          "program": [
            {"cmd" : "cp", "args" : "build.bit build.dfu"},
            {"cmd" : "dfu-suffix", "args" : "-v 1209 -p 5af0 -a build.dfu"},
            {"cmd" : "dfu-util", "args" : "-D build.dfu"}
          ]
        },
        {
          "builder" : "shell",
          "command" : "orangecrab.sh",
          "description": "Custom shell scripts using yosys and nextpnr"
        }
      ]    
    }
  ],
  "pins": {
    "basic": [
        {
          "name": "led",
          "type": "uint3",
          "io": "output"
        }
    ]
  }
}
# base on https://github.com/FPGAwars/icestudio/blob/develop/app/resources/boards/orangecrab-r02-25f/pinout.lpf

LOCATE COMP "CLK" SITE "A9"; # input
IOBUF PORT "CLK" IO_TYPE=LVCMOS33;

LOCATE COMP "LED[0]" SITE "K4"; # output
LOCATE COMP "LED[1]" SITE "M3"; # output
LOCATE COMP "LED[2]" SITE "J3"; # output

LOCATE COMP "RST" SITE "T15"; # inout
LOCATE COMP "A[0]" SITE "L4"; # inout
LOCATE COMP "A[1]" SITE "N3"; # inout
LOCATE COMP "A[2]" SITE "N4"; # inout
LOCATE COMP "A[3]" SITE "H4"; # inout
LOCATE COMP "A[4]" SITE "G4"; # inout
LOCATE COMP "A[5]" SITE "T17"; # inout
LOCATE COMP "SCK" SITE "R17"; # inout
LOCATE COMP "MOSI" SITE "N16"; # inout
LOCATE COMP "MISO" SITE "N15"; # inout
LOCATE COMP "G[0]" SITE "N17"; # inout
LOCATE COMP "G[1]" SITE "M18"; # inout
LOCATE COMP "SDA" SITE "C10"; # inout
LOCATE COMP "SCL" SITE "C9"; # inout
LOCATE COMP "G[5]" SITE "B10"; # inout
LOCATE COMP "G[6]" SITE "B9"; # inout
LOCATE COMP "G[9]" SITE "C8"; # inout
LOCATE COMP "G[10]" SITE "B8"; # inout
LOCATE COMP "G[11]" SITE "A8"; # inout
LOCATE COMP "G[12]" SITE "H2"; # inout
LOCATE COMP "G[13]" SITE "J2"; # inout

# TODO: add PROGRAMN and PULLMODEs if any

IOBUF PORT "LED[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "LED[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "LED[2]" IO_TYPE=LVCMOS33;

IOBUF PORT "RST" IO_TYPE=LVCMOS33;
IOBUF PORT "A[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "A[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "A[2]" IO_TYPE=LVCMOS33;
IOBUF PORT "A[3]" IO_TYPE=LVCMOS33;
IOBUF PORT "A[4]" IO_TYPE=LVCMOS33;
IOBUF PORT "A[5]" IO_TYPE=LVCMOS33;
IOBUF PORT "SCK" IO_TYPE=LVCMOS33;
IOBUF PORT "MOSI" IO_TYPE=LVCMOS33;
IOBUF PORT "MISO" IO_TYPE=LVCMOS33;
IOBUF PORT "G[0]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[1]" IO_TYPE=LVCMOS33;
IOBUF PORT "SDA" IO_TYPE=LVCMOS33;
IOBUF PORT "SCL" IO_TYPE=LVCMOS33;
IOBUF PORT "G[5]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[6]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[9]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[10]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[11]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[12]" IO_TYPE=LVCMOS33;
IOBUF PORT "G[13]" IO_TYPE=LVCMOS33;
#============================================================
# Additional settings
#============================================================

set_global_assignment -name ALLOW_ANY_ROM_SIZE_FOR_RECOGNITION ON
set_global_assignment -name ALLOW_ANY_RAM_SIZE_FOR_RECOGNITION ON

#============================================================
# Clocks
#============================================================

# set_location_assignment PIN_V11 -to clk
# set_location_assignment PIN_E11 -to clk
set_location_assignment PIN_Y13 -to clk
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to clk

#============================================================
# LEDs
#============================================================

set_location_assignment PIN_W15  -to leds[0]
set_location_assignment PIN_AA24 -to leds[1]
set_location_assignment PIN_V16  -to leds[2]
set_location_assignment PIN_V15  -to leds[3]
set_location_assignment PIN_AF26 -to leds[4]
set_location_assignment PIN_AE26 -to leds[5]
set_location_assignment PIN_Y16  -to leds[6]
set_location_assignment PIN_AA23 -to leds[7]

set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to leds*

#============================================================
# Keypad
#============================================================

set_location_assignment PIN_AC24 -to kpadC[0]
set_location_assignment PIN_AD26 -to kpadC[1]
set_location_assignment PIN_AF28 -to kpadC[2]
set_location_assignment PIN_AF27 -to kpadC[3]
set_location_assignment PIN_Y15  -to kpadR[0]
set_location_assignment PIN_AA15 -to kpadR[1]
set_location_assignment PIN_AG28 -to kpadR[2]
set_location_assignment PIN_AE25 -to kpadR[3]

set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to kpadC*
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to kpadR*
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to kpadR*

#============================================================
# Switches and Buttons
#============================================================

set_location_assignment PIN_AH24 -to btns[0]
set_location_assignment PIN_AG25 -to btns[1]
set_location_assignment PIN_AG23 -to btns[2]
set_location_assignment PIN_AH17 -to btns[3]
set_location_assignment PIN_AH16 -to btns[4]
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to btns*

#============================================================
# VGA (I/O board compatible)
#============================================================

set_location_assignment PIN_AE17 -to vga_r[0]
set_location_assignment PIN_AE20 -to vga_r[1]
set_location_assignment PIN_AF20 -to vga_r[2]
set_location_assignment PIN_AH18 -to vga_r[3]
set_location_assignment PIN_AH19 -to vga_r[4]
set_location_assignment PIN_AF21 -to vga_r[5]

set_location_assignment PIN_AE19 -to vga_g[0]
set_location_assignment PIN_AG15 -to vga_g[1]
set_location_assignment PIN_AF18 -to vga_g[2]
set_location_assignment PIN_AG18 -to vga_g[3]
set_location_assignment PIN_AG19 -to vga_g[4]
set_location_assignment PIN_AG20 -to vga_g[5]

set_location_assignment PIN_AG21 -to vga_b[0]
set_location_assignment PIN_AA20 -to vga_b[1]
set_location_assignment PIN_AE22 -to vga_b[2]
set_location_assignment PIN_AF22 -to vga_b[3]
set_location_assignment PIN_AH23 -to vga_b[4]
set_location_assignment PIN_AH21 -to vga_b[5]

set_location_assignment PIN_AH22 -to vga_hs
set_location_assignment PIN_AG24 -to vga_vs

set_location_assignment PIN_AH27 -to vga_en
set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to vga_en

set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to vga_*
set_instance_assignment -name CURRENT_STRENGTH_NEW 8MA -to vga_*

#============================================================
# SDRAM
#============================================================

set_location_assignment PIN_Y11 -to SDRAM_A[0]
set_location_assignment PIN_AA26 -to SDRAM_A[1]
set_location_assignment PIN_AA13 -to SDRAM_A[2]
set_location_assignment PIN_AA11 -to SDRAM_A[3]
set_location_assignment PIN_W11 -to SDRAM_A[4]
set_location_assignment PIN_Y19 -to SDRAM_A[5]
set_location_assignment PIN_AB23 -to SDRAM_A[6]
set_location_assignment PIN_AC23 -to SDRAM_A[7]
set_location_assignment PIN_AC22 -to SDRAM_A[8]
set_location_assignment PIN_C12 -to SDRAM_A[9]
set_location_assignment PIN_AB26 -to SDRAM_A[10]
set_location_assignment PIN_AD17 -to SDRAM_A[11]
set_location_assignment PIN_D12 -to SDRAM_A[12]
set_location_assignment PIN_Y17 -to SDRAM_BA[0]
set_location_assignment PIN_AB25 -to SDRAM_BA[1]
set_location_assignment PIN_E8 -to SDRAM_DQ[0]
set_location_assignment PIN_V12 -to SDRAM_DQ[1]
set_location_assignment PIN_D11 -to SDRAM_DQ[2]
set_location_assignment PIN_W12 -to SDRAM_DQ[3]
set_location_assignment PIN_AH13 -to SDRAM_DQ[4]
set_location_assignment PIN_D8 -to SDRAM_DQ[5]
set_location_assignment PIN_AH14 -to SDRAM_DQ[6]
set_location_assignment PIN_AF7 -to SDRAM_DQ[7]
set_location_assignment PIN_AE24 -to SDRAM_DQ[8]
set_location_assignment PIN_AD23 -to SDRAM_DQ[9]
set_location_assignment PIN_AE6 -to SDRAM_DQ[10]
set_location_assignment PIN_AE23 -to SDRAM_DQ[11]
set_location_assignment PIN_AG14 -to SDRAM_DQ[12]
set_location_assignment PIN_AD5 -to SDRAM_DQ[13]
set_location_assignment PIN_AF4 -to SDRAM_DQ[14]
set_location_assignment PIN_AH3 -to SDRAM_DQ[15]
set_location_assignment PIN_AG13 -to SDRAM_DQML
set_location_assignment PIN_AF13 -to SDRAM_DQMH
set_location_assignment PIN_AD20 -to SDRAM_CLK
set_location_assignment PIN_AG10 -to SDRAM_CKE
set_location_assignment PIN_AA19 -to SDRAM_nWE
set_location_assignment PIN_AA18 -to SDRAM_nCAS
set_location_assignment PIN_Y18 -to SDRAM_nCS
set_location_assignment PIN_W14 -to SDRAM_nRAS

set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to SDRAM_*
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to SDRAM_*
set_instance_assignment -name FAST_OUTPUT_REGISTER ON -to SDRAM_*
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name FAST_INPUT_REGISTER ON -to SDRAM_DQ[*]
set_instance_assignment -name ALLOW_SYNCH_CTRL_USAGE OFF -to *|SDRAM_*
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQML
set_instance_assignment -name FAST_OUTPUT_ENABLE_REGISTER ON -to SDRAM_DQMH

#============================================================
# UART
#============================================================

set_location_assignment PIN_AG11 -to uart_rx
set_location_assignment PIN_AH9  -to uart_tx
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to uart_rx
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to uart_tx

set_location_assignment PIN_AG8  -to uart2_rx
set_location_assignment PIN_AH8  -to uart2_tx
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to uart2_rx
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to uart2_tx
{
  "name": "de10nano",
  "variants": [
    {
      "name": "configurable",
      "framework" : "de10nano.v",
      "pins": [
        {"set"    : "basic"},
        {"set"    : "buttons","define" : "BUTTONS=1"},
        {"set"    : "vga",    "define" : "VGA=1"},
        {"set"    : "sdram",  "define" : "SDRAM=1"},
        {"set"    : "uart",   "define" : "UART=1"},
        {"set"    : "uart2",  "define" : "UART2=1"},
        {"set"    : "keypad", "define" : "KEYPAD=1"}
      ],
      "builders": [
      {
        "builder" : "edalize",
        "description": "Build using Edalize",
        "tool": "quartus",
        "tool_options": [
          {
            "family": "Cyclone V",
            "device": "5CSEBA6U23I7",
            "cable" : "DE-SoC",
            "board_device_index" : 2
          }
        ],
        "toplevel" : "top",
        "bitstream"  : "build.sof",
        "constraints": [
          {"name": "build.sdc", "file_type": "SDC"},
          {"name": "pins.tcl", "file_type": "tclSource"}
        ],
        "program": [
          {"cmd" : "quartus_pgm", "args" : "-m jtag -o \"p;build.sof@2\""}
        ]
      }
      ]
    }
  ],
  "pins": {
    "basic": [
      {
        "name": "leds",
        "type": "uint8",
        "io"  : "output"
      }
    ],
    "uart": [
      {
        "name": "uart_tx",
        "type": "uint1",
        "io"  : "output"
      },
      {
        "name": "uart_rx",
        "type": "uint1",
        "io"  : "input"
      }
    ],
    "uart2": [
      {
        "name": "tx",
        "type": "uint1",
        "io"  : "output"
      },
      {
        "name": "rx",
        "type": "uint1",
        "io"  : "input"
      }
    ],
    "keypad" : [
      {
        "name": "kpadC",
        "type": "uint4",
        "io"  : "output"
      },
      {
        "name": "kpadR",
        "type": "uint4",
        "io"  : "input"
      }
    ],
    "buttons" : [
      {
        "name": "btns",
        "type": "uint5",
        "io"  : "input"
      }
    ],
    "sdram": [
      {
        "name": "sdram_dq",
        "type": "uint16",
        "io": "inout"
      },
      {
        "name": "sdram_clk",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cle",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_dqm",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_we",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cas",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_ras",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_ba",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_a",
        "type": "uint1",
        "io": "output"
      }
    ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ]
  }
}
# inform quartus that the clk port brings a 50MHz clock into our design so
# that timing closure on our design can be analyzed

create_clock -name clk -period "50MHz" [get_ports clk]
derive_pll_clocks -create_base_clocks
derive_clock_uncertainty

# inform quartus that the LED output port has no critical timing requirements
# its a single output port driving an LED, there are no timing relationships
# that are critical for this

set_false_path -from * -to [get_ports leds[0]]
set_false_path -from * -to [get_ports leds[1]]
set_false_path -from * -to [get_ports leds[2]]
set_false_path -from * -to [get_ports leds[3]]
set_false_path -from * -to [get_ports leds[4]]
set_false_path -from * -to [get_ports leds[5]]
set_false_path -from * -to [get_ports leds[6]]
set_false_path -from * -to [get_ports leds[7]]
`define DE10NANO 1
$$DE10NANO = 1
$$HARDWARE = 1
$$NUM_LEDS = 8
$$NUM_BTNS = 5
$$if YOSYS then
$$config['bram_wenable_width'] = 'data'
$$config['dualport_bram_wenable0_width'] = 'data'
$$config['dualport_bram_wenable1_width'] = 'data'
$$else
$$config['dualport_bram_template'] = 'dualport_bram_altera.v.in'
$$end
$$color_depth = 6
$$color_max   = 63

`ifdef UART
`ifdef UART2
  `error_choose_either_uart_or_uart2
`endif  
`endif  

module top(
    output [7:0] leds,
`ifdef BUTTONS
    // buttons
    input  [4:0] btns,
`endif  
`ifdef SDRAM
    // sdram
    output  SDRAM_CLK,
    output  SDRAM_CKE,
    output  SDRAM_DQML,
    output  SDRAM_DQMH,
    output  SDRAM_nCS,
    output  SDRAM_nWE,
    output  SDRAM_nCAS,
    output  SDRAM_nRAS,
    output  [1:0] SDRAM_BA,
    output  [12:0] SDRAM_A,
    inout   [15:0] SDRAM_DQ,
`endif  
`ifdef VGA  
    // vga
    output  vga_hs,
    output  vga_vs,
    output  [5:0] vga_r,
    output  [5:0] vga_g,
    output  [5:0] vga_b,
`endif  
`ifdef UART
    // uart
    input  uart_rx,
    output uart_tx,
`endif  
`ifdef UART2
    // uart, second choice
    input  uart2_rx,
    output uart2_tx,
`endif  
`ifdef KEYPAD
    // keypad
    output  [3:0] kpadC,
    input   [3:0] kpadR,
`endif
    // clock
    input clk
);

wire [7:0]  __main_out_leds;

`ifdef SDRAM
wire        __main_out_sdram_clk;
wire        __main_out_sdram_cle;
wire [1:0]  __main_out_sdram_dqm;
wire        __main_out_sdram_cs;
wire        __main_out_sdram_we;
wire        __main_out_sdram_cas;
wire        __main_out_sdram_ras;
wire [1:0]  __main_out_sdram_ba;
wire [12:0] __main_out_sdram_a;
`endif

`ifdef VGA 
wire        __main_out_vga_hs;
wire        __main_out_vga_vs;
wire [5:0]  __main_out_vga_r;
wire [5:0]  __main_out_vga_g;
wire [5:0]  __main_out_vga_b;
`endif  

`ifdef UART
wire        __main_out_uart_tx;
`endif  
`ifdef UART2
wire        __main_out_uart_tx;
`endif  

`ifdef KEYPAD
wire [3:0]  __main_out_kpadC;
`endif  

// reset

reg [31:0] RST_d;
reg [31:0] RST_q;

reg ready = 0;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge clk) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 32'b111111111111111111111111111111;
  end
end

wire reset_main;
assign reset_main = RST_q[0];
wire run_main;
assign run_main = 1'b1;

M_main __main(
  .reset(reset_main),
  .in_run(run_main),
  .out_leds(__main_out_leds),
`ifdef BUTTONS  
  .in_btns(btns),
`endif
`ifdef SDRAM
  .inout_sdram_dq(SDRAM_DQ),
  .out_sdram_clk(__main_out_sdram_clk),
  .out_sdram_cle(__main_out_sdram_cle),
  .out_sdram_dqm(__main_out_sdram_dqm),
  .out_sdram_cs(__main_out_sdram_cs),
  .out_sdram_we(__main_out_sdram_we),
  .out_sdram_cas(__main_out_sdram_cas),
  .out_sdram_ras(__main_out_sdram_ras),
  .out_sdram_ba(__main_out_sdram_ba),
  .out_sdram_a(__main_out_sdram_a),
`endif  
`ifdef VGA
  .out_video_hs(__main_out_vga_hs),
  .out_video_vs(__main_out_vga_vs),
  .out_video_r(__main_out_vga_r),
  .out_video_g(__main_out_vga_g),
  .out_video_b(__main_out_vga_b),
`endif
`ifdef UART
  .out_uart_tx(__main_out_uart_tx),
  .in_uart_rx(uart_rx),
`endif  
`ifdef UART2
  .out_uart_tx(__main_out_uart_tx),
  .in_uart_rx(uart2_rx),
`endif  
`ifdef KEYPAD
  .out_kpadC(__main_out_kpadC),
  .in_kpadR(kpadR),
`endif
  .clock(clk)
);

assign  leds         = __main_out_leds;

`ifdef SDRAM
assign  SDRAM_CLK    = __main_out_sdram_clk;
assign  SDRAM_CKE    = __main_out_sdram_cle;
assign  SDRAM_DQML   = __main_out_sdram_dqm[0];
assign  SDRAM_DQMH   = __main_out_sdram_dqm[1];
assign  SDRAM_nCS    = __main_out_sdram_cs;
assign  SDRAM_nWE    = __main_out_sdram_we;
assign  SDRAM_nCAS   = __main_out_sdram_cas;
assign  SDRAM_nRAS   = __main_out_sdram_ras;
assign  SDRAM_BA     = __main_out_sdram_ba;
assign  SDRAM_A      = __main_out_sdram_a;
`endif  

`ifdef VGA
assign  vga_hs       = __main_out_vga_hs;
assign  vga_vs       = __main_out_vga_vs;
assign  vga_r        = __main_out_vga_r;
assign  vga_g        = __main_out_vga_g;
assign  vga_b        = __main_out_vga_b;
`endif  

`ifdef UART
assign uart_tx       = __main_out_uart_tx;
`endif  
`ifdef UART2
assign uart2_tx      = __main_out_uart_tx;
`endif  

`ifdef KEYPAD
assign  kpadC        = __main_out_kpadC;
`endif  
  
endmodule
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR:"/c/Program Files (x86)/Graphviz2.38/bin/"
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build.v

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

yosys -p 'synth_ice40 ; show -width -stretch -colors 4242' build.v

dot -Tpdf:cairo show.dot -O
`define YOSYS 1
`default_nettype none
$$HARDWARE = 1
$$NUM_LEDS = 4

module top(
  // LED outputs
  output [3:0] leds,
  input        clk
);

    wire [7:0] __main_leds;

    reg reset = 1;

    always @(posedge clk) begin
      if (reset) begin
        reset <= 0;
      end
    end

    M_main __main(
    .clock        (clk),
    .reset        (reset),
    .out_leds     (__main_leds),
    .in_run       (~reset)
    );

    assign leds = __main_leds;

endmodule
{
  "name": "techgraph",
  "variants": [
    {
      "name"      : "techgraph",
      "framework" : "techgraph.v",
      "pins"      : [ 
        {"set"    : "basic"}
      ],
      "builders": [
        {
          "builder" : "shell",
          "command" : "techgraph.sh",
          "description": "Custom shell scripts using yosys and nextpnr"
        }
      ]    
    }
  ],
  "pins": {
    "basic": [
        {
          "name": "leds",
          "type": "uint8",
          "io": "output"
        }
    ]
  }
}
`define VERILATOR         1
`define COLOR_DEPTH       1

/*verilator lint_off pinmissing */
/*verilator lint_off undriven */

$$VERILATOR   = 1
$$NUM_LEDS    = 0
$$SIMULATION  = 1
$$color_depth = 1
$$color_max   = 1

`timescale 1ns / 1ps
`default_nettype none

module top(
  // NTSC
  output reg [`COLOR_DEPTH*3-1:0] rgb,
  output hsync,
  output vsync,
  input clk,
  input reset
  );

wire [`COLOR_DEPTH-1:0]  __main_video_r;
wire [`COLOR_DEPTH-1:0]  __main_video_g;
wire [`COLOR_DEPTH-1:0]  __main_video_b;
wire                     __main_video_hs;
wire                     __main_video_vs;

// main

wire   run_main;
assign run_main = 1'b1;
wire done_main;

M_main __main(
  .clock(clk),
  .reset(reset),
`ifdef NTSC
  .out_video_r(__main_video_r),
  .out_video_g(__main_video_g),
  .out_video_b(__main_video_b),
  .out_video_hs(__main_video_hs),
  .out_video_vs(__main_video_vs),
`endif  
  .in_run(run_main),
  .out_done(done_main)
);

assign rgb     = {__main_video_b[0], __main_video_g[0], __main_video_r[0]};
assign hsync    = __main_video_hs;
assign vsync    = __main_video_vs;

endmodule
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

if hash make 2>/dev/null; then
  export MAKE=make
else
  export MAKE=mingw32-make  
fi

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR

if [[ -z "${VERILATOR_ROOT}" ]]; then
case "$(uname -s)" in
Linux)
unset VERILATOR_ROOT
;;
*)
export VERILATOR_ROOT=$SILICE_DIR/../tools/fpga-binutils/mingw64/
;;
esac
echo "VERILATOR_ROOT is set to ${VERILATOR_ROOT}"
else
echo "VERILATOR_ROOT already defined, using its value"
fi

u=$(echo "$1" | sed s:/:__:g | tr -d ".")

echo "using directory $u"

cd $BUILD_DIR

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

if [[ -z "${VGA}" ]] && [[ -z "${SDRAM}" ]]; then
VERILATOR_LIB="verilator_bare"
else
VERILATOR_LIB="verilator_vga"
fi

#echo "using verilator framework $VERILATOR_LIB"

#verilator -Wno-PINMISSING -Wno-WIDTH -O3 -cc build.v --top-module top
#cd obj_dir
#$MAKE -f Vtop.mk
#$MAKE -f Vtop.mk $SILICE_DIR/../frameworks/verilator/$VERILATOR_LIB.o verilated.o 
#g++ -O3 $SILICE_DIR/../frameworks/verilator/$VERILATOR_LIB.o verilated.o Vtop__ALL.a $SILICE_DIR/../frameworks/verilator/libverilator_silice.a -o ../run_simul
#cd ..

#./run_simul
{
  "name": "8bitworkshop",
  "variants": [
    {
      "name"      : "configurable",
      "framework" : "8bitworkshop.v",
      "pins"      : [ 
        {"set"    : "ntsc", "define" : "NTSC=1"} 
      ],
      "builders": [
        {
          "builder" : "shell",
          "command" : "8bitworkshop.sh",
          "description": "Simulates with 8bitworkshop"
        }
      ]
    }
  ],
  "pins": {
    "ntsc": [
      {
        "name": "hsync",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vsync",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "rgb",
        "type": "uint3",
        "io": "output"
      }
    ],
    "paddles": [
      {
        "name": "hpaddle",
        "type": "uint1",
        "io": "input"
      },
      {
        "name": "vpaddle",
        "type": "uint1",
        "io": "input"
      }
    ],
    "switches": [
      {
        "name": "switches_p1",
        "type": "uint8",
        "io": "input"
      },
      {
        "name": "switches_p2",
        "type": "uint8",
        "io": "input"
      }
    ],
    "keyboard": [
      {
        "name": "keycode",
        "type": "uint8",
        "io": "input"
      },
      {
        "name": "keystrobe",
        "type": "uint1",
        "io": "output"
      }
    ]
  }
}
{
  "name": "fomu",
  "variants": [
    {
      "name"      : "hacker",
      "framework" : "fomu.v",
      "pins"      : [ 
        {"set"    : "basic"},
        {"set"    : "usb",  "define" : "USB=1"},
        {"set"    : "spi",  "define" : "SPI=1"},
        {"set"    : "pads", "define" : "PADS=1"}
      ],
      "builders": [
        {
          "builder" : "shell",
          "command" : "fomu.sh",
          "description": "Custom shell scripts using yosys and nextpnr"
        }
      ]    
    }
  ],
  "pins": {
    "basic": [
        {
          "name": "leds",
          "type": "uint3",
          "io": "output"
        }
    ],
    "usb": [
      {
        "name": "usb_dp",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "usb_dn",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "usb_dp_pu",
        "type": "uint1",
        "io": "output"
      }
    ],
    "spi": [
      {
        "name": "spi_mosi",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "spi_miso",
        "type": "uint1",
        "io": "input"
      },
      {
        "name": "spi_clk",
        "type": "uint1",
        "io": "output"
      },      
      {
        "name": "spi_cs",
        "type": "uint1",
        "io": "output"
      }
    ],
    "pads": [
      {
        "name": "user_pads",
        "type": "uint4",
        "io": "input"
      }
    ]
  }
}
# Configuration for the Fomu hacker board.
set_io rgb0 A5		# Blue LED
set_io rgb1 B5		# Green LED
set_io rgb2 C5		# Red LED
set_io clki F5		# Clock input from 48MHz Oscillator
set_io spi_mosi F1	# SPI Master Out, Slave In Pin
set_io spi_miso E1	# SPI Master In, Slave Out Pin
set_io spi_clk D1	# SPI Master Clock Output Pin
set_io spi_cs C1	# SPI Chip Select
set_io user_1 F4	# User touch pad 1
set_io user_2 E5	# User touch pad 2
set_io user_3 E4	# User touch pad 3
set_io user_4 F2	# User touch pad 4
set_io usb_dn A2	# USB D- pad
set_io usb_dp A4	# USB D+ pad
set_io usb_dp_pu D5	# USB D+ pull up (indicates device connected)
// credits: rob-ng15 - see also https://github.com/rob-ng15/Silice-Playground/
`define FOMU 1
`default_nettype none
$$FOMU     = 1
$$HARDWARE = 1
$$NUM_LEDS = 3

// Correctly map pins for the iCE40UP5K SB_RGBA_DRV hard macro.
// The variables EVT, PVT and HACKER are set from the yosys commandline e.g. yosys -D HACKER=1
`ifdef EVT
`define BLUEPWM  RGB0PWM
`define REDPWM   RGB1PWM
`define GREENPWM RGB2PWM
`elsif HACKER
`define BLUEPWM  RGB0PWM
`define GREENPWM RGB1PWM
`define REDPWM   RGB2PWM
`elsif PVT
`define GREENPWM RGB0PWM
`define REDPWM   RGB1PWM
`define BLUEPWM  RGB2PWM
`else
`error_board_not_supported
`endif

module top(
  // LED outputs
  output  rgb0,
  output  rgb1,
  output  rgb2,
  // USB Pins
  output  usb_dp,
  output  usb_dn,
  output  usb_dp_pu,
`ifdef SPI
  // SPI
  output  spi_mosi,
  input   spi_miso,
  output  spi_clk,
  output  spi_cs,
`endif
`ifdef PADS
  // USER pads
  input [3:0] user_pads,
`endif
  // 48MHz Clock Input
  input   clki
);

`ifdef USB
    wire __main_usb_dp;
    wire __main_usb_dn;
    wire __main_usb_dp_pu;
    assign usb_dp    = __main_usb_dp;
    assign usb_dn    = __main_usb_dn;
    assign usb_dp_pu = __main_usb_dp_pu;
`else
    // Assign USB pins to "0" so as to disconnect Fomu from
    // the host system.  Otherwise it would try to talk to
    // us over USB, which wouldn't work since we have no stack.
    assign usb_dp = 1'b0;
    assign usb_dn = 1'b0;
    assign usb_dp_pu = 1'b0;
`endif

`ifdef SPI
    wire __main_spi_mosi;
    wire __main_spi_clk;
    wire __main_spi_cs;
    assign spi_mosi = __main_spi_mosi;
    assign spi_clk  = __main_spi_clk;
    assign spi_cs   = __main_spi_cs;
`endif

    // Connect to system clock (with buffering)
    wire clk;
    SB_GB clk_gb (
        .USER_SIGNAL_TO_GLOBAL_BUFFER(clki),
        .GLOBAL_BUFFER_OUTPUT(clk)
    );

    wire [2:0] __main_leds;

    reg [31:0] RST_d;
    reg [31:0] RST_q;

    reg ready = 0;

    always @* begin
    RST_d = RST_q >> 1;
    end

    always @(posedge clk) begin
    if (ready) begin
        RST_q <= RST_d;
    end else begin
        ready <= 1;
        RST_q <= 32'b111111111111111111111111111111;
    end
    end

    wire reset_main;
    assign reset_main = RST_q[0];
    wire run_main;
    assign run_main = 1'b1;

    M_main __main(
    .clock        (clk),
    .reset        (RST_q[0]),
    .out_leds     (__main_leds),
`ifdef USB
    .out_usb_dp   (__main_usb_dp),
    .out_usb_dn   (__main_usb_dn),
    .out_usb_dp_pu(__main_usb_dp_pu),
`endif
`ifdef SPI
    .out_spi_mosi (__main_spi_mosi),
    .in_spi_miso  (spi_miso),
    .out_spi_clk  (__main_spi_clk),
    .out_spi_cs   (__main_spi_cs),
`endif
`ifdef PADS
    .in_user_pads(user_pads),
`endif
    .in_run       (run_main)
    );

    SB_RGBA_DRV #(
        .CURRENT_MODE("0b1"),       // half current
        .RGB0_CURRENT("0b000011"),  // 4 mA
        .RGB1_CURRENT("0b000011"),  // 4 mA
        .RGB2_CURRENT("0b000011")   // 4 mA
    ) RGBA_DRIVER (
        .CURREN(1'b1),
        .RGBLEDEN(1'b1),
        .`BLUEPWM (__main_leds[0]),     // Blue
        .`REDPWM  (__main_leds[1]),      // Red
        .`GREENPWM(__main_leds[2]),    // Green
        .RGB0(rgb0),
        .RGB1(rgb1),
        .RGB2(rgb2)
    );

endmodule
#!/bin/bash

# credits: rob-ng15 -- see also https://github.com/rob-ng15/Silice-Playground

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build*

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

yosys -D HACKER=1 -p 'synth_ice40 -top top -json build.json' build.v

nextpnr-ice40 --up5k --package uwg30 --opt-timing --pcf $BOARD_DIR/fomu-hacker.pcf --json build.json --asc build.asc

icepack build.asc build.bit
icetime -d up5k -mtr build.rpt build.asc

cp build.bit build.dfu
dfu-suffix -v 1209 -p 70b1 -a build.dfu
dfu-util -D build.dfu
`define ULX3S 1
`default_nettype none
$$ULX3S    = 1
$$HARDWARE = 1
$$NUM_LEDS = 8
$$NUM_BTNS = 7
$$color_depth = 6
$$color_max   = 63
$$config['dualport_bram_supported'] = 'no'

module top(
  // basic
  output [7:0] leds,
  // buttons
  input  [6:0] btns,
`ifdef SDRAM
  // sdram
  output sdram_clk,
  output sdram_cke,
  output [1:0]  sdram_dqm,
  output sdram_csn,
  output sdram_wen,
  output sdram_casn,
  output sdram_rasn,
  output [1:0]  sdram_ba,
  output [12:0] sdram_a,
  inout  [15:0] sdram_d,
`endif  
`ifdef AUDIO
  output [3:0] audio_l,
  output [3:0] audio_r,
`endif  
`ifdef OLED  
  // oled
  output  oled_clk,
  output  oled_mosi,
  output  oled_dc,
  output  oled_resn,
  output  oled_csn,
`endif  
`ifdef SDCARD
  // sdcard
  output  sd_clk,
  output  sd_csn,
  output  sd_mosi,
  input   sd_miso,
`endif  
`ifdef GPIO
  // gpio
  output [27:0] gp,
  input  [27:0] gn,
`endif  
`ifdef VGA
  // vga
  output [27:0] gp,
  input  [27:0] gn,
`endif  
`ifdef HDMI
  // hdmi
  output [3:0]  gpdi_dp, // {clock,R,G,B}
  output [3:0]  gpdi_dn,
`endif  
`ifdef UART
  // uart
  output  ftdi_rxd,
  input   ftdi_txd,
`endif
`ifdef UART2
  // uart2
`endif
  input  clk_25mhz
  );

wire [7:0]  __main_out_leds;

`ifdef OLED
wire        __main_oled_clk;
wire        __main_oled_mosi;
wire        __main_oled_dc;
wire        __main_oled_resn;
wire        __main_oled_csn;
`endif

`ifdef SDRAM
wire        __main_out_sdram_clk;
wire        __main_out_sdram_cle;
wire [1:0]  __main_out_sdram_dqm;
wire        __main_out_sdram_cs;
wire        __main_out_sdram_we;
wire        __main_out_sdram_cas;
wire        __main_out_sdram_ras;
wire [1:0]  __main_out_sdram_ba;
wire [12:0] __main_out_sdram_a;
`endif

`ifdef UART2
`ifndef GPIO
`error_UART2_needs_GPIO
`endif
`endif

`ifdef UART
wire        __main_out_uart_tx;
`endif

`ifdef VGA
wire        __main_out_vga_hs;
wire        __main_out_vga_vs;
wire [5:0]  __main_out_vga_r;
wire [5:0]  __main_out_vga_g;
wire [5:0]  __main_out_vga_b;
`endif

`ifdef SDCARD
wire        __main_sd_clk;
wire        __main_sd_csn;
wire        __main_sd_mosi;
`endif

`ifdef HDMI
wire [3:0]  __main_out_gpdi_dp;
wire [3:0]  __main_out_gpdi_dn;
`endif

`ifdef AUDIO
wire [3:0]  __main_out_audio_l;
wire [3:0]  __main_out_audio_r;
`endif

wire ready = btns[0];

reg [31:0] RST_d;
reg [31:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge clk_25mhz) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    RST_q <= 32'b111111111111111111111111111111;
  end
end

wire run_main;
assign run_main = 1'b1;

M_main __main(
  .reset         (RST_q[0]),
  .in_run        (run_main),
  .out_leds      (__main_out_leds),
`ifdef BUTTONS  
  .in_btns       (btns),
`endif
`ifdef SDRAM
  .inout_sdram_dq(sdram_d),
  .out_sdram_clk (__main_out_sdram_clk),
  .out_sdram_cle (__main_out_sdram_cle),
  .out_sdram_dqm (__main_out_sdram_dqm),
  .out_sdram_cs  (__main_out_sdram_cs),
  .out_sdram_we  (__main_out_sdram_we),
  .out_sdram_cas (__main_out_sdram_cas),
  .out_sdram_ras (__main_out_sdram_ras),
  .out_sdram_ba  (__main_out_sdram_ba),
  .out_sdram_a   (__main_out_sdram_a),
`endif  
`ifdef SDCARD
  .out_sd_csn    (__main_sd_csn),
  .out_sd_clk    (__main_sd_clk),
  .out_sd_mosi   (__main_sd_mosi),
  .in_sd_miso    (sd_miso),
`endif  
`ifdef AUDIO
  .out_audio_l  (__main_out_audio_l),
  .out_audio_r  (__main_out_audio_r),
`endif  
`ifdef OLED
  .out_oled_clk (__main_oled_clk),
  .out_oled_mosi(__main_oled_mosi),
  .out_oled_dc  (__main_oled_dc),
  .out_oled_resn(__main_oled_resn),
  .out_oled_csn (__main_oled_csn),
`endif 
`ifdef GPIO
`ifdef UART2
  .out_gp       (gp[27:1]),
  .in_gn        (gn[27:1]),
  .out_uart2_tx (gp[0]),
  .in_uart2_rx  (gn[0]),
`else
  .out_gp       (gp),
  .in_gn        (gn),
`endif  
`endif  
`ifdef UART
  .out_uart_tx  (__main_out_uart_tx),
  .in_uart_rx   (ftdi_txd),
`endif  
`ifdef VGA
  .out_video_hs (__main_out_vga_hs),
  .out_video_vs (__main_out_vga_vs),
  .out_video_r  (__main_out_vga_r),
  .out_video_g  (__main_out_vga_g),
  .out_video_b  (__main_out_vga_b),  
`endif  
`ifdef HDMI
  .out_gpdi_dp  (__main_out_gpdi_dp),
  .out_gpdi_dn  (__main_out_gpdi_dn),
`endif
  .clock         (clk_25mhz)
);

assign leds          = __main_out_leds;

`ifdef SDRAM
assign sdram_clk     = __main_out_sdram_clk;
assign sdram_cke     = __main_out_sdram_cle;
assign sdram_dqm     = __main_out_sdram_dqm;
assign sdram_csn     = __main_out_sdram_cs;
assign sdram_wen     = __main_out_sdram_we;
assign sdram_casn    = __main_out_sdram_cas;
assign sdram_rasn    = __main_out_sdram_ras;
assign sdram_ba      = __main_out_sdram_ba;
assign sdram_a       = __main_out_sdram_a;
`endif

`ifdef AUDIO
assign audio_l       = __main_out_audio_l;
assign audio_r       = __main_out_audio_r;
`endif  

`ifdef VGA
assign gp[0]         = __main_out_vga_vs;
assign gp[1]         = __main_out_vga_hs;
assign gp[2]         = __main_out_vga_r[5];
assign gp[3]         = __main_out_vga_r[4];
assign gp[4]         = __main_out_vga_r[3];
assign gp[5]         = __main_out_vga_r[2];
assign gp[6]         = __main_out_vga_r[1];
assign gp[7]         = __main_out_vga_r[0];
assign gp[8]         = __main_out_vga_g[5];
assign gp[9]         = __main_out_vga_g[4];
assign gp[10]        = __main_out_vga_g[3];
assign gp[11]        = __main_out_vga_g[2];
assign gp[12]        = __main_out_vga_g[1];
assign gp[13]        = __main_out_vga_g[0];
assign gp[14]        = __main_out_vga_b[0];
assign gp[15]        = __main_out_vga_b[1];
assign gp[16]        = __main_out_vga_b[2];
assign gp[17]        = __main_out_vga_b[3];
assign gp[18]        = __main_out_vga_b[4];
assign gp[19]        = __main_out_vga_b[5];
`endif

`ifdef SDCARD
assign sd_clk        = __main_sd_clk;
assign sd_csn        = __main_sd_csn;
assign sd_mosi       = __main_sd_mosi;
`endif

`ifdef OLED
assign oled_clk      = __main_oled_clk;
assign oled_mosi     = __main_oled_mosi;
assign oled_dc       = __main_oled_dc;
assign oled_resn     = __main_oled_resn;
assign oled_csn      = __main_oled_csn;
`endif

`ifdef UART
assign ftdi_rxd      = __main_out_uart_tx;
`endif  

`ifdef HDMI
assign gpdi_dp       = __main_out_gpdi_dp;
assign gpdi_dn       = __main_out_gpdi_dn;
`endif

endmodule
# https://github.com/emard/ulx3s/blob/master/doc/constraints/ulx3s_v20.lpf

BLOCK RESETPATHS;
BLOCK ASYNCPATHS;
## ULX3S v2.x.x and v3.0.x

# The clock "usb" and "gpdi" sheet
LOCATE COMP "clk_25mhz" SITE "G2";
IOBUF PORT "clk_25mhz" PULLMODE=NONE IO_TYPE=LVCMOS33;
FREQUENCY PORT "clk_25mhz" 25 MHZ;

# JTAG and SPI FLASH voltage 3.3V and options to boot from SPI flash
# write to FLASH possible any time from JTAG:
#SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=ENABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;
# write to FLASH possible from user bitstream:
SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 MASTER_SPI_PORT=DISABLE SLAVE_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE;

## USBSERIAL FTDI-FPGA serial port "usb" sheet
LOCATE COMP "ftdi_rxd" SITE "L4"; # FPGA transmits to ftdi
LOCATE COMP "ftdi_txd" SITE "M1"; # FPGA receives from ftdi
LOCATE COMP "ftdi_nrts" SITE "M3"; # FPGA receives
LOCATE COMP "ftdi_ndtr" SITE "N1"; # FPGA receives
LOCATE COMP "ftdi_txden" SITE "L3"; # FPGA receives
IOBUF PORT "ftdi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "ftdi_txd" PULLMODE=UP IO_TYPE=LVCMOS33;
IOBUF PORT "ftdi_nrts" PULLMODE=UP IO_TYPE=LVCMOS33;
IOBUF PORT "ftdi_ndtr" PULLMODE=UP IO_TYPE=LVCMOS33;
IOBUF PORT "ftdi_txden" PULLMODE=UP IO_TYPE=LVCMOS33;

## LED indicators "blinkey" and "gpio" sheet
LOCATE COMP "leds[7]" SITE "H3";
LOCATE COMP "leds[6]" SITE "E1";
LOCATE COMP "leds[5]" SITE "E2";
LOCATE COMP "leds[4]" SITE "D1";
LOCATE COMP "leds[3]" SITE "D2";
LOCATE COMP "leds[2]" SITE "C1";
LOCATE COMP "leds[1]" SITE "C2";
LOCATE COMP "leds[0]" SITE "B2";
IOBUF PORT "leds[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "leds[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;

## Pushbuttons "blinkey", "flash", "power", "gpdi" sheet
LOCATE COMP "btns[0]" SITE "D6";  # BTN_PWRn (inverted logic)
LOCATE COMP "btns[1]" SITE "R1";  # FIRE1
LOCATE COMP "btns[2]" SITE "T1";  # FIRE2
LOCATE COMP "btns[3]" SITE "R18"; # UP
LOCATE COMP "btns[4]" SITE "V1";  # DOWN
LOCATE COMP "btns[5]" SITE "U1";  # LEFT
LOCATE COMP "btns[6]" SITE "H16"; # RIGHT
IOBUF PORT "btns[0]" PULLMODE=UP IO_TYPE=LVCMOS33;
IOBUF PORT "btns[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "btns[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "btns[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "btns[4]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "btns[5]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "btns[6]" PULLMODE=DOWN IO_TYPE=LVCMOS33;

## DIP switch "blinkey", "gpio" sheet
LOCATE COMP "sw[0]" SITE "E8"; # SW1
LOCATE COMP "sw[1]" SITE "D8"; # SW2
LOCATE COMP "sw[2]" SITE "D7"; # SW3
LOCATE COMP "sw[3]" SITE "E7"; # SW4
IOBUF PORT "sw[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "sw[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "sw[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33;
IOBUF PORT "sw[3]" PULLMODE=DOWN IO_TYPE=LVCMOS33;

## SPI OLED DISPLAY SSD1331 (Color) or SSD1306 (B/W) "blinkey", "usb" sheet
LOCATE COMP "oled_clk" SITE "P4";
LOCATE COMP "oled_mosi" SITE "P3";
LOCATE COMP "oled_dc" SITE "P1";
LOCATE COMP "oled_resn" SITE "P2";
LOCATE COMP "oled_csn" SITE "N2";
IOBUF PORT "oled_clk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_dc" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_resn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "oled_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

## SPI Flash chip "flash" sheet
LOCATE COMP "flash_csn" SITE "R2";
#LOCATE COMP "flash_clk" SITE "U3";
LOCATE COMP "flash_mosi" SITE "W2";
LOCATE COMP "flash_miso" SITE "V2";
LOCATE COMP "flash_holdn" SITE "W1";
LOCATE COMP "flash_wpn" SITE "Y2";
#LOCATE COMP "flash_csspin" SITE "AJ3";
#LOCATE COMP "flash_initn" SITE "AG4";
#LOCATE COMP "flash_done" SITE "AJ4";
#LOCATE COMP "flash_programn" SITE "AH4";
#LOCATE COMP "flash_cfg_select[0]" SITE "AM4";
#LOCATE COMP "flash_cfg_select[1]" SITE "AL4";
#LOCATE COMP "flash_cfg_select[2]" SITE "AK4";
IOBUF PORT "flash_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_mosi" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_miso" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_holdn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "flash_wpn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_csspin" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_initn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_cfg_select[0]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_cfg_select[1]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "flash_cfg_select[2]" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;

## SD card "sdcard", "usb" sheet
LOCATE COMP "sd_clk"  SITE "H2"; # sd_clk WiFi_GPIO14
LOCATE COMP "sd_mosi" SITE "J1"; # sd_cmd_di (MOSI) WiFi GPIO15
LOCATE COMP "sd_miso" SITE "J3"; # sd_dat0_do (MISO) WiFi GPIO2
LOCATE COMP "sd_csn"  SITE "K2"; # sd_dat3_csn WiFi_GPIO13
IOBUF PORT "sd_clk"   PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sd_mosi"  PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sd_miso"  PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sd_csn"   PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

## ADC SPI (MAX11123) "analog", "ram" sheet
LOCATE COMP "adc_csn" SITE "R17";
LOCATE COMP "adc_mosi" SITE "R16";
LOCATE COMP "adc_miso" SITE "U16";
LOCATE COMP "adc_sclk" SITE "P17";
IOBUF PORT "adc_csn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "adc_mosi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "adc_miso" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "adc_sclk" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

## Audio 4-bit DAC "analog", "gpio" sheet
# Output impedance 75 ohm.
# Strong enough to drive 16 ohm earphones.
LOCATE COMP "audio_l[3]" SITE "B3"; # JACK TIP (left audio)
LOCATE COMP "audio_l[2]" SITE "C3";
LOCATE COMP "audio_l[1]" SITE "D3";
LOCATE COMP "audio_l[0]" SITE "E4";
LOCATE COMP "audio_r[3]" SITE "C5"; # JACK RING1 (right audio)
LOCATE COMP "audio_r[2]" SITE "D5";
LOCATE COMP "audio_r[1]" SITE "B5";
LOCATE COMP "audio_r[0]" SITE "A3";
LOCATE COMP "audio_v[3]" SITE "E5"; # JACK RING2 (video or digital audio)
LOCATE COMP "audio_v[2]" SITE "F5";
LOCATE COMP "audio_v[1]" SITE "F2";
LOCATE COMP "audio_v[0]" SITE "H5";
IOBUF PORT "audio_l[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_l[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_l[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_l[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_r[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_r[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_r[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_r[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_v[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_v[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_v[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "audio_v[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;

## WiFi ESP-32 "wifi", "usb", "flash" sheet
# other pins are shared with GP/GN, SD card and JTAG
LOCATE COMP "wifi_en" SITE "F1"; # enable/reset WiFi
LOCATE COMP "wifi_rxd" SITE "K3"; # FPGA transmits to WiFi
LOCATE COMP "wifi_txd" SITE "K4"; # FPGA receives from WiFi
LOCATE COMP "wifi_gpio0" SITE "L2";
LOCATE COMP "wifi_gpio5" SITE "N4"; # WIFI LED
LOCATE COMP "wifi_gpio16" SITE "L1"; # Serial1 RX
LOCATE COMP "wifi_gpio17" SITE "N3"; # Serial1 TX
# LOCATE COMP "prog_done" SITE "Y3"; # not GPIO, always active
IOBUF PORT "wifi_en" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "wifi_rxd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "wifi_txd" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "wifi_gpio0" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "wifi_gpio5" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "wifi_gpio16" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "wifi_gpio17" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
# IOBUF PORT "prog_done" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

## PCB antenna 433 MHz (may be also used for FM) "usb" sheet
LOCATE COMP "ant_433mhz" SITE "G1";
IOBUF PORT "ant_433mhz" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;

## Second USB port "US2" going directly into FPGA "usb", "ram" sheet
LOCATE COMP "usb_fpga_dp" SITE "E16"; # single ended or differential input only
LOCATE COMP "usb_fpga_dn" SITE "F16";
IOBUF PORT "usb_fpga_dp" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16;
IOBUF PORT "usb_fpga_dn" PULLMODE=NONE IO_TYPE=LVCMOS33D DRIVE=16;
LOCATE COMP "usb_fpga_bd_dp" SITE "D15"; # single-ended bidirectional
LOCATE COMP "usb_fpga_bd_dn" SITE "E15";
IOBUF PORT "usb_fpga_bd_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "usb_fpga_bd_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
LOCATE COMP "usb_fpga_pu_dp" SITE "B12"; # pull up/down control
LOCATE COMP "usb_fpga_pu_dn" SITE "C12";
IOBUF PORT "usb_fpga_pu_dp" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;
IOBUF PORT "usb_fpga_pu_dn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=16;

## JTAG ESP-32 "usb" sheet
# connected to FT231X and ESP-32
# commented out because those are dedicated pins, not directly useable as GPIO
# but could be used by some vendor-specific JTAG bridging (boundary scan) module
#LOCATE COMP "jtag_tdi" SITE "R5"; # FTDI_nRI   FPGA receives
#LOCATE COMP "jtag_tdo" SITE "V4"; # FTDI_nCTS  FPGA transmits
#LOCATE COMP "jtag_tck" SITE "T5"; # FTDI_nDSR  FPGA receives
#LOCATE COMP "jtag_tms" SITE "U5"; # FTDI_nDCD  FPGA receives
#IOBUF PORT "jtag_tdi" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "jtag_tdo" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "jtag_tck" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
#IOBUF PORT "jtag_tms" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

## SDRAM "ram" sheet
LOCATE COMP "sdram_clk" SITE "F19";
LOCATE COMP "sdram_cke" SITE "F20";
LOCATE COMP "sdram_csn" SITE "P20";
LOCATE COMP "sdram_wen" SITE "T20";
LOCATE COMP "sdram_rasn" SITE "R20";
LOCATE COMP "sdram_casn" SITE "T19";
LOCATE COMP "sdram_a[0]" SITE "M20";
LOCATE COMP "sdram_a[1]" SITE "M19";
LOCATE COMP "sdram_a[2]" SITE "L20";
LOCATE COMP "sdram_a[3]" SITE "L19";
LOCATE COMP "sdram_a[4]" SITE "K20";
LOCATE COMP "sdram_a[5]" SITE "K19";
LOCATE COMP "sdram_a[6]" SITE "K18";
LOCATE COMP "sdram_a[7]" SITE "J20";
LOCATE COMP "sdram_a[8]" SITE "J19";
LOCATE COMP "sdram_a[9]" SITE "H20";
LOCATE COMP "sdram_a[10]" SITE "N19";
LOCATE COMP "sdram_a[11]" SITE "G20";
LOCATE COMP "sdram_a[12]" SITE "G19";
LOCATE COMP "sdram_ba[0]" SITE "P19";
LOCATE COMP "sdram_ba[1]" SITE "N20";
LOCATE COMP "sdram_dqm[0]" SITE "U19";
LOCATE COMP "sdram_dqm[1]" SITE "E20";
LOCATE COMP "sdram_d[0]" SITE "J16";
LOCATE COMP "sdram_d[1]" SITE "L18";
LOCATE COMP "sdram_d[2]" SITE "M18";
LOCATE COMP "sdram_d[3]" SITE "N18";
LOCATE COMP "sdram_d[4]" SITE "P18";
LOCATE COMP "sdram_d[5]" SITE "T18";
LOCATE COMP "sdram_d[6]" SITE "T17";
LOCATE COMP "sdram_d[7]" SITE "U20";
LOCATE COMP "sdram_d[8]" SITE "E19";
LOCATE COMP "sdram_d[9]" SITE "D20";
LOCATE COMP "sdram_d[10]" SITE "D19";
LOCATE COMP "sdram_d[11]" SITE "C20";
LOCATE COMP "sdram_d[12]" SITE "E18";
LOCATE COMP "sdram_d[13]" SITE "F18";
LOCATE COMP "sdram_d[14]" SITE "J18";
LOCATE COMP "sdram_d[15]" SITE "J17";
IOBUF PORT "sdram_clk" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_cke" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_csn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_wen" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_rasn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_casn" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_a[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_ba[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_ba[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_dqm[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_dqm[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[0]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[1]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[2]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[3]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[4]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[5]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[6]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[7]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[8]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[9]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[10]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[11]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[12]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[13]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[14]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "sdram_d[15]" PULLMODE=NONE IO_TYPE=LVCMOS33 DRIVE=4;

# GPDI differential interface (Video) "gpdi" sheet
LOCATE COMP "gpdi_dp[0]" SITE "A16"; # Blue +
LOCATE COMP "gpdi_dn[0]" SITE "B16"; # Blue -
LOCATE COMP "gpdi_dp[1]" SITE "A14"; # Green +
LOCATE COMP "gpdi_dn[1]" SITE "C14"; # Green -
LOCATE COMP "gpdi_dp[2]" SITE "A12"; # Red +
LOCATE COMP "gpdi_dn[2]" SITE "A13"; # Red -
LOCATE COMP "gpdi_dp[3]" SITE "A17"; # Clock +
LOCATE COMP "gpdi_dn[3]" SITE "B18"; # Clock -
LOCATE COMP "gpdi_ethp" SITE "A19"; # Ethernet +
LOCATE COMP "gpdi_ethn" SITE "B20"; # Ethernet -
LOCATE COMP "gpdi_cec" SITE "A18";
LOCATE COMP "gpdi_sda" SITE "B19"; # I2C shared with RTC
LOCATE COMP "gpdi_scl" SITE "E12"; # I2C shared with RTC C12->E12
IOBUF PORT "gpdi_dp[0]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dn[0]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dp[1]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dn[1]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dp[2]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dn[2]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dp[3]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_dn[3]" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_ethp" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_ethn" IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_cec" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_sda" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;
IOBUF PORT "gpdi_scl" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

# GPIO (default single-ended) "gpio", "ram", "gpdi" sheet
# Physical connector pins:
# *** when FEMALE ANGLED (90 deg PMOD) soldered ***
# Jm_n- = Jm_n, Jm_n+ = Jm_n+1
# example: J1_5- is J1_5 phsyical, J1_5+ is J1_6 physical
# *** when MALE VERTICAL soldered ***
# Jm_n+ = Jm_n, Jm_n- = Jm_n+1
# example: J1_5+ is J1_5 physical, J1_5- is J1_6 physical
# Pins enumerated gp[0-27], gn[0-27].
# With differential mode enabled on Lattice,
# gp[] (+) are used, gn[] (-) are ignored from design
# as they handle inverted signal by default.
# To enable differential, rename LVCMOS33->LVCMOS33D
# To enable clock i/o, add this (example):
#FREQUENCY PORT "gp[12]" 25.00 MHZ;
LOCATE COMP "gp[0]" SITE "B11"; # J1_5+  GP0 PCLK
LOCATE COMP "gn[0]" SITE "C11"; # J1_5-  GN0 PCLK
LOCATE COMP "gp[1]" SITE "A10"; # J1_7+  GP1 PCLK
LOCATE COMP "gn[1]" SITE "A11"; # J1_7-  GN1 PCLK
LOCATE COMP "gp[2]" SITE "A9";  # J1_9+  GP2 GR_PCLK
LOCATE COMP "gn[2]" SITE "B10"; # J1_9-  GN2 GR_PCLK
LOCATE COMP "gp[3]" SITE "B9";  # J1_11+ GP3
LOCATE COMP "gn[3]" SITE "C10"; # J1_11- GN3
LOCATE COMP "gp[4]" SITE "A7";  # J1_13+ GP4
LOCATE COMP "gn[4]" SITE "A8";  # J1_13- GN4
LOCATE COMP "gp[5]" SITE "C8";  # J1_15+ GP5
LOCATE COMP "gn[5]" SITE "B8";  # J1_15- GN5
LOCATE COMP "gp[6]" SITE "C6";  # J1_17+ GP6
LOCATE COMP "gn[6]" SITE "C7";  # J1_17- GN6
IOBUF PORT "gp[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[0]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[1]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[2]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[3]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[4]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[5]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[6]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
LOCATE COMP "gp[7]" SITE "A6";  # J1_23+ GP7
LOCATE COMP "gn[7]" SITE "B6";  # J1_23- GN7
LOCATE COMP "gp[8]" SITE "A4";  # J1_25+ GP8
LOCATE COMP "gn[8]" SITE "A5";  # J1_25- GN8  DIFF
LOCATE COMP "gp[9]" SITE "A2";  # J1_27+ GP9  DIFF
LOCATE COMP "gn[9]" SITE "B1";  # J1_27- GN9  DIFF
LOCATE COMP "gp[10]" SITE "C4";  # J1_29+ GP10 DIFF
LOCATE COMP "gn[10]" SITE "B4";  # J1_29- GN10 DIFF
LOCATE COMP "gp[11]" SITE "F4";  # J1_31+ GP11 DIFF WIFI_GPIO26
LOCATE COMP "gn[11]" SITE "E3";  # J1_31- GN11 DIFF WIFI_GPIO25
LOCATE COMP "gp[12]" SITE "G3";  # J1_33+ GP12 DIFF WIFI_GPIO33 PCLK
LOCATE COMP "gn[12]" SITE "F3";  # J1_33- GN12 DIFF WIFI_GPIO32 PCLK
LOCATE COMP "gp[13]" SITE "H4";  # J1_35+ GP13 DIFF WIFI_GPIO35
LOCATE COMP "gn[13]" SITE "G5";  # J1_35- GN13 DIFF WIFI_GPIO34
IOBUF PORT "gp[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[7]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[8]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[9]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[10]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[11]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[12]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[13]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
LOCATE COMP "gp[14]" SITE "U18"; # J2_5+  GP14 DIFF ADC1
LOCATE COMP "gn[14]" SITE "U17"; # J2_5-  GN14 DIFF ADC0
LOCATE COMP "gp[15]" SITE "N17"; # J2_7+  GP15 DIFF ADC3
LOCATE COMP "gn[15]" SITE "P16"; # J2_7-  GN15 DIFF ADC2
LOCATE COMP "gp[16]" SITE "N16"; # J2_9+  GP16 DIFF ADC5
LOCATE COMP "gn[16]" SITE "M17"; # J2_9-  GN16 DIFF ADC4
LOCATE COMP "gp[17]" SITE "L16"; # J2_11+ GP17 DIFF ADC7 GR_PCLK
LOCATE COMP "gn[17]" SITE "L17"; # J2_11- GN17 DIFF ADC6
LOCATE COMP "gp[18]" SITE "H18"; # J2_13+ GP18 DIFF
LOCATE COMP "gn[18]" SITE "H17"; # J2_13- GN18 DIFF
LOCATE COMP "gp[19]" SITE "F17"; # J2_15+ GP19 DIFF
LOCATE COMP "gn[19]" SITE "G18"; # J2_15- GN19 DIFF
LOCATE COMP "gp[20]" SITE "D18"; # J2_17+ GP20 DIFF
LOCATE COMP "gn[20]" SITE "E17"; # J2_17- GN20 DIFF
IOBUF PORT "gp[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[14]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[15]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[16]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[17]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[18]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[19]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[20]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
LOCATE COMP "gp[21]" SITE "C18"; # J2_23+ GP21 DIFF
LOCATE COMP "gn[21]" SITE "D17"; # J2_23- GN21 DIFF
LOCATE COMP "gp[22]" SITE "B15"; # J2_25+ GP22
LOCATE COMP "gn[22]" SITE "C15"; # J2_25- GN22
LOCATE COMP "gp[23]" SITE "B17"; # J2_27+ GP23
LOCATE COMP "gn[23]" SITE "C17"; # J2_27- GN23
LOCATE COMP "gp[24]" SITE "C16"; # J2_29+ GP24
LOCATE COMP "gn[24]" SITE "D16"; # J2_29- GN24
LOCATE COMP "gp[25]" SITE "D14"; # J2_31+ GP25
LOCATE COMP "gn[25]" SITE "E14"; # J2_31- GN25
LOCATE COMP "gp[26]" SITE "B13"; # J2_33+ GP26
LOCATE COMP "gn[26]" SITE "C13"; # J2_33- GN26
LOCATE COMP "gp[27]" SITE "D13"; # J2_35+ GP27
LOCATE COMP "gn[27]" SITE "E13"; # J2_35- GN27
IOBUF PORT "gp[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[21]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[22]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[23]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[24]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[25]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[26]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gp[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;
IOBUF PORT "gn[27]" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=8;

## PROGRAMN (reload bitstream from FLASH, exit from bootloader)
# PCB v2.0.5 and higher
LOCATE COMP "user_programn" SITE "M4";
IOBUF PORT "user_programn" PULLMODE=UP IO_TYPE=LVCMOS33 DRIVE=4;

## SHUTDOWN "power", "ram" sheet (connected from PCB v1.7.5)
# on PCB v1.7 shutdown is not connected to FPGA
LOCATE COMP "shutdown" SITE "G16"; # FPGA receives
IOBUF PORT "shutdown" PULLMODE=DOWN IO_TYPE=LVCMOS33 DRIVE=4;
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build*
silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

# exit ################### DEBUG DEBUG DEBUG

yosys -p 'scratchpad -copy abc9.script.flow3 abc9.script; synth_ecp5 -abc9 -json build.json' build.v

nextpnr-ecp5 --85k --package CABGA381 --freq 25 --json build.json --textcfg build.config --lpf $BOARD_DIR/ulx3s.lpf --timing-allow-fail

sed -i '/.sysconfig/d' build.config

ecppack --compress --svf-rowsize 100000 --svf build.svf build.config build.bit

fujprog build.bit
{
  "name": "ulx3s",
  "variants": [
    {
      "name": "85k",
      "framework" : "ulx3s.v",
      "pins": [
        {"set"    : "basic"},
        {"set"    : "buttons","define" : "BUTTONS=1"},
        {"set"    : "vga",    "define" : "VGA=1"},
        {"set"    : "oled",   "define" : "OLED=1"},
        {"set"    : "sdram",  "define" : "SDRAM=1"},
        {"set"    : "sdcard", "define" : "SDCARD=1"},
        {"set"    : "hdmi",   "define" : "HDMI=1"},
        {"set"    : "gpio",   "define" : "GPIO=1"},
        {"set"    : "audio",  "define" : "AUDIO=1"},
        {"set"    : "uart",   "define" : "UART=1"},
        {"set"    : "uart2",  "define" : "UART2=1"}
      ],
      "builders": [
      {
        "builder" : "edalize",
        "description": "Build using Edalize",
        "tool": "trellis",
        "tool_options": [
          {
              "yosys_synth_options": ["-abc9"],
              "nextpnr_options": ["--85k", "--freq 25", "--package CABGA381", "--timing-allow-fail"],
              "pnr": "next"
          }
        ],
        "bitstream"  : "build.bit",
        "constraints": [{"name": "ulx3s.lpf", "file_type": "LPF"}],
        "program": [{"cmd" : "fujprog", "args" : "build.bit"}]
      },
      {
        "builder" : "shell",
        "command" : "ulx3s.sh",
        "description": "Custom shell scripts using yosys and nextpnr"
      }
      ]
    }
  ],
  "pins": {
    "basic": [
      {
        "name": "leds",
        "type": "uint8",
        "io": "output"
      }
    ],
    "buttons" : [
      {
        "name": "btns",
        "type": "uint7",
        "io": "input"
      }
    ],
    "audio" : [
      {
        "name": "audio_l",
        "type": "uint4",
        "io": "output"
      },
      {
        "name": "audio_r",
        "type": "uint4",
        "io": "output"
      }
    ],
    "oled": [
      {
        "name": "oled_clk",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_mosi",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_dc",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_resn",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_csn",
        "type": "uint1",
        "io": "output"
      }
    ],
    "sdcard": [
      {
        "name": "sd_csn",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sd_clk",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sd_mosi",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sd_miso",
        "type": "uint1",
        "io": "input"
      }
    ],
    "sdram": [
      {
        "name": "sdram_dq",
        "type": "uint16",
        "io": "inout"
      },
      {
        "name": "sdram_clk",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cle",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_dqm",
        "type": "uint2",
        "io": "output"
      },
      {
        "name": "sdram_cs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_we",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cas",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_ras",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_ba",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_a",
        "type": "uint1",
        "io": "output"
      }
    ],
    "hdmi": [
      {
        "name": "gpdi_dq",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "gpdi_dn",
        "type": "uint1",
        "io": "output"
      }
    ],
    "gpio": [
      {
        "name": "gp",
        "type": "uint28",
        "io": "inout"
      },
      {
        "name": "gn",
        "type": "uint28",
        "io": "inout"
      }
    ],
    "uart": [
      {
        "name": "uart_tx",
        "type": "uint1",
        "io"  : "output"
      },
      {
        "name": "uart_rx",
        "type": "uint1",
        "io"  : "input"
      }
    ],
    "uart2": [
      {
        "name": "uart2_tx",
        "type": "uint1",
        "io"  : "output"
      },
      {
        "name": "uart2_rx",
        "type": "uint1",
        "io"  : "input"
      }
    ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ]
  }
}
`define ICESTICK 1
`default_nettype none
$$ICESTICK=1
$$HARDWARE=1
$$NUM_LEDS=5
$$VGA=1
$$color_depth=6
$$color_max  =63
$$config['bram_wenable_width'] = 'data'
$$config['dualport_bram_wenable0_width'] = 'data'
$$config['dualport_bram_wenable1_width'] = 'data'
$$config['simple_dualport_bram_wenable0_width'] = 'data'
$$config['simple_dualport_bram_wenable1_width'] = 'data'

module top(
  output D1,
  output D2,
  output D3,
  output D4,
  output D5,
`ifdef OLED
  output BR3,
  output BR4,
  output BR5,
  output BR6,
  output BR7,
`endif
`ifdef VGA
  output PMOD1, // r0
  output PMOD2, // r1
  output PMOD3, // r2 
  output PMOD4, // r3
  output PMOD8, // r4
  output PMOD9, // r5
  
  output TR10, // g0
  output TR9,  // g1
  output TR8,  // g2 
  output TR7,  // g3
  output TR6,  // g4
  output TR5,  // g5
  
  output BR10, // b0
  output BR9,  // b1
  output BR8,  // b2 
  output BR7,  // b3
  output BR6,  // b4
  output BR5,  // b5

  output PMOD7,  // hs
  output PMOD10, // vs
`endif
  input  CLK
  );

wire [4:0] __main_leds;

`ifdef OLED
wire __main_oled_clk;
wire __main_oled_mosi;
wire __main_oled_csn;
wire __main_oled_resn;
wire __main_oled_dc;
`endif

`ifdef VGA
wire __main_out_vga_hs;
wire __main_out_vga_vs;
wire __main_out_vga_v0;
wire [5:0] __main_out_vga_r;
wire [5:0] __main_out_vga_g;
wire [5:0] __main_out_vga_b;
`endif

// the init sequence pauses for some cycles
// waiting for BRAM init to stabalize
// this is a known issue with ice40 FPGAs
// https://github.com/YosysHQ/icestorm/issues/76

reg ready = 0;
reg [31:0] RST_d;
reg [31:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge CLK) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 32'b11111111111111111111111111111111;
  end
end

wire run_main;
assign run_main = 1'b1;

M_main __main(
  .clock(CLK),
  .reset(RST_d),
  .out_leds(__main_leds),
`ifdef OLED
  .out_oled_mosi(__main_oled_mosi),
  .out_oled_clk(__main_oled_clk),
  .out_oled_csn(__main_oled_csn),
  .out_oled_dc(__main_oled_dc),
  .out_oled_resn(__main_oled_resn),
`endif
`ifdef VGA
  .out_video_hs(__main_out_vga_hs),
  .out_video_vs(__main_out_vga_vs),
  .out_video_r(__main_out_vga_r),
  .out_video_g(__main_out_vga_g),
  .out_video_b(__main_out_vga_b),
`endif
  .in_run(run_main)
);

assign D1 = __main_leds[0+:1];
assign D2 = __main_leds[1+:1];
assign D3 = __main_leds[2+:1];
assign D4 = __main_leds[3+:1];
assign D5 = __main_leds[4+:1];

// OLED

`ifdef OLED

assign BR3 = __main_oled_mosi;
assign BR4 = __main_oled_clk;
assign BR5 = __main_oled_csn;
assign BR6 = __main_oled_dc;
assign BR7 = __main_oled_resn;

`endif

// VGA

`ifdef VGA

assign PMOD1  = __main_out_vga_r[5+:1];
assign PMOD2  = __main_out_vga_r[4+:1];
assign PMOD3  = __main_out_vga_r[3+:1];
assign PMOD4  = __main_out_vga_r[2+:1];
assign PMOD8  = __main_out_vga_r[1+:1];
assign PMOD9  = __main_out_vga_r[0+:1];

assign TR10   = __main_out_vga_g[5+:1];
assign TR9    = __main_out_vga_g[4+:1];
assign TR8    = __main_out_vga_g[3+:1];
assign TR7    = __main_out_vga_g[2+:1];
assign TR6    = __main_out_vga_g[1+:1];
assign TR5    = __main_out_vga_g[0+:1];

assign BR10   = __main_out_vga_b[5+:1];
assign BR9    = __main_out_vga_b[4+:1];
assign BR8    = __main_out_vga_b[3+:1];
assign BR7    = __main_out_vga_b[2+:1];
assign BR6    = __main_out_vga_b[1+:1];
assign BR5    = __main_out_vga_b[0+:1];

assign PMOD7  = __main_out_vga_hs;
assign PMOD10 = __main_out_vga_vs;

`endif


endmodule
# -----------------------------------------------------------------------------
#- Icestick constraint file (.pcf)
#- By Juan Gonzalez (Obijuan)
#- April - 2016
#- GPL license
# -----------------------------------------------------------------------------
# --  Pinout: https://github.com/Obijuan/open-fpga-verilog-tutorial/blob/master/tutorial/doc/images/icestick_pinout.png
# --  Guide: https://github.com/Obijuan/open-fpga-verilog-tutorial/blob/master/tutorial/doc/icestickusermanual.pdf

# -- Icestick leds map
#
#           D1
#        D4 D5 D2
#           D3
#
# --    D1-D4: Red leds
# --    D5: green led


# ------------ Red leds ------------------------------------------------------
set_io --warn-no-port D1 99
set_io --warn-no-port D2 98
set_io --warn-no-port D3 97
set_io --warn-no-port D4 96

# ------------ Green led -----------------------------------------------------
set_io --warn-no-port D5 95

# ------------ IrDA ----------------------------------------------------------
set_io --warn-no-port IrDA_TX 105
set_io --warn-no-port IrDA_RX 106

#-- SD = 0, enable IrDA
set_io --warn-no-port SD 107

# ------------ PMOD connector ------------------------------------------------
#
#   Pmod standar numeration (Oriented according the icestick, with the
#               usb connector pointing to the left and IRda to the right)
#
#      --------
#     |  12  6 |
#     |  11  5 |
#     |  10  4 |
#     |  9   3 |
#     |  8   2 |
#     |  7   1 | <
#      --------
#
#   FPGA pins:
#
#     ----------
#    | 3V3  3V3 |
#    | GND  GND |
#    | 91    81 |
#    | 90    80 |
#    | 88    79 |
#    | 87    78 | <
#     ----------
#
set_io --warn-no-port PMOD1 78
set_io --warn-no-port PMOD2 79
set_io --warn-no-port PMOD3 80
set_io --warn-no-port PMOD4 81
set_io --warn-no-port PMOD7 87
set_io --warn-no-port PMOD8 88
set_io --warn-no-port PMOD9 90
set_io --warn-no-port PMOD10 91

# ------------------------ EXPANSION I/O ------------------------------------
#
# -- Numeration
#
#  Top Row (TR):
#                                       v
#          --------------------------------
#         |  10  9  8  7  6  5 4  3  2  1  |
#          --------------------------------
#
#  Bottom Row (BR):
#
#                                       v
#          --------------------------------
#         |  10  9  8  7  6  5 4  3  2  1  |
#          --------------------------------
#
# --- FPGA pins
#
#  Top Row (TR)
#                                                       v
#        --------------------------------------------------
#       | 119  118  117  116  115  114  113  112  GND  3v3 |
#        --------------------------------------------------
#
#
#  Bottom Row (BR)
#
#                                                       v
#         -------------------------------------------------
#        | 44   45   47   48   56   60   61   62  GND  3v3 |
#         -------------------------------------------------
#
# -- Top Row
set_io --warn-no-port TR3 112
set_io --warn-no-port TR4 113
set_io --warn-no-port TR5 114
set_io --warn-no-port TR6 115
set_io --warn-no-port TR7 116
set_io --warn-no-port TR8 117
set_io --warn-no-port TR9 118
set_io --warn-no-port TR10 119
#
# -- Bottom Row
set_io --warn-no-port BR3 62
set_io --warn-no-port BR4 61
set_io --warn-no-port BR5 60
set_io --warn-no-port BR6 56
set_io --warn-no-port BR7 48
set_io --warn-no-port BR8 47
set_io --warn-no-port BR9 45
set_io --warn-no-port BR10 44

# -------------------------- SYSTEM CLOCK ------------------------------------
set_io --warn-no-port CLK 21

# -------------------------- FTDI --------------------------------------------
# --- FTDI 0:
set_io --warn-no-port RES  66
set_io --warn-no-port DONE 65
set_io --warn-no-port SS   71
set_io --warn-no-port MISO 67
set_io --warn-no-port MOSI 68
set_io --warn-no-port SCK  70
#
# --- FTDI 1: (Serial port)
set_io --warn-no-port DCD 1
set_io --warn-no-port DSR 2
set_io --warn-no-port DTR 3
set_io --warn-no-port CTS 4
set_io --warn-no-port RTS 7
set_io --warn-no-port TX  8
set_io --warn-no-port RX  9
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build*

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

if ! type "nextpnr-ice40" > /dev/null; then
  # try arachne-pnr instead
  echo "nextpnr-ice40 not found, trying arachne-pnr instead"
  yosys -q -p "synth_ice40 -blif build.blif" build.v
  arachne-pnr -p $BOARD_DIR/icestick.pcf build.blif -o build.txt
  icepack build.txt build.bin
else
  yosys -p 'synth_ice40 -top top -json build.json' build.v
  nextpnr-ice40 --hx1k --json build.json --pcf $BOARD_DIR/icestick.pcf --asc build.asc --package tq144 --freq 12
  icepack build.asc build.bin
fi

iceprog build.bin
{
  "name": "icestick",
  "variants": [
    {
      "name"      : "configurable",
      "framework" : "icestick.v",
      "pins"      : [ 
        {"set"    : "basic"},
        {"set"    : "vga",  "define" : "VGA=1"},
        {"set"    : "oled", "define" : "OLED=1"}
      ],
      "builders": [
        {
          "builder" : "edalize",
          "description": "Build using Edalize",
          "tool": "icestorm",
          "tool_options": [
            {
                "nextpnr_options": ["--hx1k", "--freq 12", "--package tq144", "--timing-allow-fail"],
                "pnr": "next"
            }
          ],
          "bitstream"  : "build.bin",
          "constraints": [{"name": "icestick.pcf", "file_type": "PCF"}],
          "program": [{"cmd" : "iceprog", "args" : "build.bin"}]
        },
        {
          "builder" : "shell",
          "command" : "icestick.sh",
          "description": "Custom shell scripts using yosys and nextpnr"
        }
      ]    
    }
  ],
  "pins": {
    "basic": [
      {
        "name": "leds",
        "type": "uint5",
        "io": "output"
      }
    ],
    "oled": [
      {
        "name": "oled_clk",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_mosi",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_csn",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_resn",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "oled_dc",
        "type": "uint1",
        "io": "output"
      }
    ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ]
  }
}
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

if hash make 2>/dev/null; then
  export MAKE=make
else
  export MAKE=mingw32-make  
fi

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR

if [[ -z "${VERILATOR_ROOT}" ]]; then
case "$(uname -s)" in
Linux)
unset VERILATOR_ROOT
;;
*)
export VERILATOR_ROOT=$SILICE_DIR/../tools/fpga-binutils/mingw64/
;;
esac
echo "VERILATOR_ROOT is set to ${VERILATOR_ROOT}"
else
echo "VERILATOR_ROOT already defined, using its value"
fi

u=$(echo "$1" | sed s:/:__:g | tr -d ".")

echo "using directory $u"

cd $BUILD_DIR

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

if [[ -z "${VGA}" ]] && [[ -z "${SDRAM}" ]]; then
VERILATOR_LIB="verilator_bare"
else
VERILATOR_LIB="verilator_vga"
fi

echo "using verilator framework $VERILATOR_LIB"

verilator -Wno-PINMISSING -Wno-WIDTH -O3 -cc build.v --top-module top
cd obj_dir
$MAKE -f Vtop.mk
$MAKE -f Vtop.mk $SILICE_DIR/../frameworks/verilator/$VERILATOR_LIB.o verilated.o 
g++ -O3 $SILICE_DIR/../frameworks/verilator/$VERILATOR_LIB.o verilated.o Vtop__ALL.a $SILICE_DIR/../frameworks/verilator/libverilator_silice.a -o ../run_simul
cd ..

./run_simul
{
  "name": "verilator",
  "variants": [
    {
      "name"      : "configurable",
      "framework" : "verilator.v",
      "pins"      : [ 
        {"set"    : "basic"},
        {"set"    : "vga", "define" : "VGA=1"}, 
        {"set"    : "sdram", "define" : "SDRAM=1"} 
      ],
      "builders": [
        {
          "builder" : "shell",
          "command" : "verilator.sh",
          "description": "Simulates with verilator"
        }
      ]
    }
  ],
  "pins": {
    "basic": [
        {
          "name": "leds",
          "type": "uint8",
          "io": "output"
        }
    ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ],
    "sdram": [
      {
        "name": "sdram_clock",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_dq_i",
        "type": "uint16",
        "io": "input"
      },
      {
        "name": "sdram_dq_o",
        "type": "uint16",
        "io": "output"
      },
      {
        "name": "sdram_dq_en",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cle",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_dqm",
        "type": "uint2",
        "io": "output"
      },
      {
        "name": "sdram_cs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_we",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_cas",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_ras",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_ba",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "sdram_a",
        "type": "uint1",
        "io": "output"
      }
    ]     
  }
}
`define VERILATOR         1
`define COLOR_DEPTH       6
`define SDRAM_WORD_WIDTH 16

$$VERILATOR   = 1
$$NUM_LEDS    = 8
$$SIMULATION  = 1
$$color_depth = 6
$$color_max   = 63

`timescale 1ns / 1ps
`default_nettype none

module top(
  // SDRAM
  output reg  sdram_clock,
  output reg  sdram_cle,
  output reg [1:0] sdram_dqm,
  output reg  sdram_cs,
  output reg  sdram_we,
  output reg  sdram_cas,
  output reg  sdram_ras,
  output reg [1:0]  sdram_ba,
  output reg [12:0] sdram_a,
  input      [15:0] sdram_dq_i,
  output reg [15:0] sdram_dq_o,
  output reg sdram_dq_en,
  // VGA
  output video_clock,
  output reg [`COLOR_DEPTH-1:0] video_r,
  output reg [`COLOR_DEPTH-1:0] video_g,
  output reg [`COLOR_DEPTH-1:0] video_b,
  output video_hs,
  output video_vs,
  output [5:0] sdram_word_width,
  output [4:0] video_color_depth,
  input       clk
  );

// this is used by the verilator framework
// -> to know the output color depth
assign video_color_depth = `COLOR_DEPTH;
// -> to know the sdram word width
assign sdram_word_width  = `SDRAM_WORD_WIDTH;

wire        __main_sdram_clock;
wire        __main_sdram_cle;
wire [1:0]  __main_sdram_dqm;
wire        __main_sdram_cs;
wire        __main_sdram_we;
wire        __main_sdram_cas;
wire        __main_sdram_ras;
wire [1:0]  __main_sdram_ba;
wire [12:0] __main_sdram_a;
wire [15:0] __main_sdram_dq_o;
wire        __main_sdram_dq_en;

wire                     __main_video_clock;
wire [`COLOR_DEPTH-1:0]  __main_video_r;
wire [`COLOR_DEPTH-1:0]  __main_video_g;
wire [`COLOR_DEPTH-1:0]  __main_video_b;
wire                     __main_video_hs;
wire                     __main_video_vs;

wire [7:0]  __main_leds;

// reset

reg ready = 0;
reg [3:0] RST_d;
reg [3:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge clk) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 4'b1111;
  end
end

// main

wire   run_main;
assign run_main = 1'b1;
wire done_main;

M_main __main(
  .clock(clk),
  .reset(RST_d[0]),
  .out_leds(__main_leds),
`ifdef SDRAM
  .out_sdram_clock(__main_sdram_clock),
  .out_sdram_cle(__main_sdram_cle),
  .out_sdram_dqm(__main_sdram_dqm),
  .out_sdram_cs(__main_sdram_cs),
  .out_sdram_we(__main_sdram_we),
  .out_sdram_cas(__main_sdram_cas),
  .out_sdram_ras(__main_sdram_ras),
  .out_sdram_ba(__main_sdram_ba),
  .out_sdram_a(__main_sdram_a),
  .in_sdram_dq_i(sdram_dq_i),
  .out_sdram_dq_o(__main_sdram_dq_o),
  .out_sdram_dq_en(__main_sdram_dq_en),
`endif  
`ifdef VGA
  .out_video_clock(__main_video_clock),
  .out_video_r(__main_video_r),
  .out_video_g(__main_video_g),
  .out_video_b(__main_video_b),
  .out_video_hs(__main_video_hs),
  .out_video_vs(__main_video_vs),
`endif  
  .in_run(run_main),
  .out_done(done_main)
);

assign sdram_clock  = __main_sdram_clock;
assign sdram_cle    = __main_sdram_cle;
assign sdram_dqm    = __main_sdram_dqm;
assign sdram_cs     = __main_sdram_cs;
assign sdram_we     = __main_sdram_we;
assign sdram_cas    = __main_sdram_cas;
assign sdram_ras    = __main_sdram_ras;
assign sdram_ba     = __main_sdram_ba;
assign sdram_a      = __main_sdram_a;
assign sdram_dq_o   = __main_sdram_dq_o;
assign sdram_dq_en  = __main_sdram_dq_en;

assign video_clock = __main_video_clock;
assign video_r     = __main_video_r;
assign video_g     = __main_video_g;
assign video_b     = __main_video_b;
assign video_hs    = __main_video_hs;
assign video_vs    = __main_video_vs;

always @* begin
  if (done_main && !RST_d[0]) $finish;
end

endmodule
#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/:$SILICE_DIR
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins

cd $BUILD_DIR

rm -rf build* *.rdf *.sty impl

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

cat << EOF > build.tcl
prj_create -name "build" -impl "impl" -dev LIFCL-40-9BG400C
prj_set_impl_opt {include path} {""}
prj_add_source "build.v" -work work
prj_add_source "$BOARD_DIR/crosslink_nx_evn.pdc" -work work
prj_set_impl_opt top "top"
prj_save
prj_run Synthesis -impl impl -forceOne
prj_run Map -impl impl
prj_run PAR -impl impl
prj_run Export -impl impl -task Bitgen
prj_close
EOF

radiantc build.tcl > toto.log 2>&1 # toto.log - French touch ;-)

openFPGALoader impl/build_impl.bit
# ----------------------------------------------------------------------------
#
# CrosslinkNX evn constraint file (.pdc)
# Link
# https://www.latticesemi.com/en/Products/DevelopmentBoardsAndKits/CrossLink-NXEvaluationBoard
#
# ----------------------------------------------------------------------------

# -------------------------- SYSTEM CLOCK ------------------------------------
ldc_set_location -site {L13} [get_ports CLK]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports CLK]

ldc_set_location -site {C12} [get_ports OSC_P]
ldc_set_location -site {C11} [get_ports OSC_N]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33D} [get_ports OSC_P]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33D} [get_ports OSC_N]

# ------------------------------ UART ----------------------------------------
ldc_set_location -site {F18} [get_ports RX]
ldc_set_location -site {F16} [get_ports TX]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33D} [get_ports OSC_P]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33D} [get_ports OSC_N]

# ------------------------- LED ----------------------------------------------
ldc_set_location -site {E17} [get_ports  LED0]
ldc_set_location -site {F13} [get_ports  LED1]
ldc_set_location -site {G13} [get_ports  LED2]
ldc_set_location -site {F14} [get_ports  LED3]
ldc_set_location -site {L16} [get_ports  LED4]
ldc_set_location -site {L15} [get_ports  LED5]
ldc_set_location -site {L20} [get_ports  LED6]
ldc_set_location -site {L19} [get_ports  LED7]
ldc_set_location -site {R17} [get_ports  LED8]
ldc_set_location -site {R18} [get_ports  LED9]
ldc_set_location -site {U20} [get_ports LED10]
ldc_set_location -site {T20} [get_ports LED11]
ldc_set_location -site {W20} [get_ports LED12]
ldc_set_location -site {V20} [get_ports LED13]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED0]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED1]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED2]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED3]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED4]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED5]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED6]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED7]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED8]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports  LED9]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports LED10]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports LED11]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports LED12]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports LED13]

# ------------------------- Button -------------------------------------------
ldc_set_location -site {G14} [get_ports SW2]
ldc_set_location -site {G15} [get_ports SW3]
ldc_set_location -site {G19} [get_ports SW4]
ldc_set_location -site {E11} [get_ports SW5]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SW2]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SW3]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SW4]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SW5]

# ----------------------- DIP Switch -----------------------------------------
ldc_set_location -site {N14} [get_ports SWITCH0]
ldc_set_location -site {M14} [get_ports SWITCH1]
ldc_set_location -site {M16} [get_ports SWITCH2]
ldc_set_location -site {M15} [get_ports SWITCH3]
ldc_set_location -site {N15} [get_ports SWITCH4]
ldc_set_location -site {N16} [get_ports SWITCH5]
ldc_set_location -site {M17} [get_ports SWITCH6]
ldc_set_location -site {M18} [get_ports SWITCH7]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH0]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH1]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH2]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH3]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH4]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH5]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH6]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports SWITCH7]

# --------------------------- SPI Flash --------------------------------------
ldc_set_location -site {} [get_ports FLASH_SCK]
ldc_set_location -site {} [get_ports FLASH_SSB]
ldc_set_location -site {} [get_ports FLASH_IO0]
ldc_set_location -site {} [get_ports FLASH_IO1]
ldc_set_location -site {} [get_ports FLASH_IO2]
ldc_set_location -site {} [get_ports FLASH_IO3]

# ------------ PMOD0 connector --------- -------------------------------------
ldc_set_location -site {D10} [get_ports PMOD0_1 ]
ldc_set_location -site {D9}  [get_ports PMOD0_2 ]
ldc_set_location -site {D7}  [get_ports PMOD0_3 ]
ldc_set_location -site {D8}  [get_ports PMOD0_4 ]
ldc_set_location -site {D6}  [get_ports PMOD0_7 ]
ldc_set_location -site {D5}  [get_ports PMOD0_8 ]
ldc_set_location -site {D4}  [get_ports PMOD0_9 ]
ldc_set_location -site {D3}  [get_ports PMOD0_10]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_1 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_2 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_3 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_4 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_7 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_8 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_9 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD0_10]

# ------------ PMOD1 connector -----------------------------------------------
ldc_set_location -site {E10} [get_ports PMOD1_1 ]
ldc_set_location -site {E9}  [get_ports PMOD1_2 ]
ldc_set_location -site {E7}  [get_ports PMOD1_3 ]
ldc_set_location -site {E8}  [get_ports PMOD1_4 ]
ldc_set_location -site {E4}  [get_ports PMOD1_7 ]
ldc_set_location -site {E3}  [get_ports PMOD1_8 ]
ldc_set_location -site {E2}  [get_ports PMOD1_9 ]
ldc_set_location -site {F1}  [get_ports PMOD1_10]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_1 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_2 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_3 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_4 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_7 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_8 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_9 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD1_10]

# ------------ PMOD2 connector -----------------------------------------------
ldc_set_location -site { J2} [get_ports PMOD2_1 ]
ldc_set_location -site { J1} [get_ports PMOD2_2 ]
ldc_set_location -site { K2} [get_ports PMOD2_3 ]
ldc_set_location -site { K1} [get_ports PMOD2_4 ]
ldc_set_location -site { K3} [get_ports PMOD2_7 ]
ldc_set_location -site { K4} [get_ports PMOD2_8 ]
ldc_set_location -site {D17} [get_ports PMOD2_9 ]
ldc_set_location -site {E18} [get_ports PMOD2_10]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_1 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_2 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_3 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_4 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_7 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_8 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_9 ]
ldc_set_port -iobuf {IO_TYPE=LVCMOS33} [get_ports PMOD2_10]

ldc_set_sysconfig {CONFIG_MODE=SPI_SERIAL MCCLK_FREQ=3.5}
`define CROSSLINKNX_EVN 1
$$CROSSLINKNX_EVN=1
$$HARDWARE=1
$$NUM_LEDS=5
$$VGA=1
$$color_depth=6
$$color_max  =63
$$config['bram_wenable_width'] = 'data'
$$config['dualport_bram_wenable0_width'] = 'data'
$$config['dualport_bram_wenable1_width'] = 'data'

module top(
  output LED0,
  output LED1,
  output LED2,
  output LED3,
  output LED4,
`ifdef VGA
  output PMOD0_1, // r0
  output PMOD0_2, // r1
  output PMOD0_3, // r2
  output PMOD0_4, // r3
  
  output PMOD0_7, // b0
  output PMOD0_8, // b1
  output PMOD0_9, // b2
  output PMOD0_10,// b3
  
  output PMOD1_1, // g0
  output PMOD1_2, // g1
  output PMOD1_3, // g2
  output PMOD1_4, // g3
  
  output PMOD1_7, // hs
  output PMOD1_8, // vs
`endif
  input  CLK
);

wire [4:0] __main_leds;

// clock from design is used in case
// it relies on a PLL: in such cases
// we cannot use the clock fed into
// the PLL here
wire design_clk;

`ifdef VGA
wire __main_out_vga_hs;
wire __main_out_vga_vs;
wire [5:0] __main_out_vga_r;
wire [5:0] __main_out_vga_g;
wire [5:0] __main_out_vga_b;
`endif

BB u0_BB (.B(CLK),
	.I(1'b0),
	.T(1'b1),
	.O(clk_s)
);

reg ready = 0;
reg [31:0] RST_d;
reg [31:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge design_clk) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 32'b111111111111111111111111111111;
  end
end

wire run_main;
assign run_main = 1'b1;

M_main __main(
  .clock(clk_s),
  .out_clock(design_clk),
  .reset(RST_d[0]),
  .out_leds(__main_leds),
`ifdef VGA
  .out_video_hs(__main_out_vga_hs),
  .out_video_vs(__main_out_vga_vs),
  .out_video_r(__main_out_vga_r),
  .out_video_g(__main_out_vga_g),
  .out_video_b(__main_out_vga_b),
`endif
  .in_run(run_main)
);

assign LED0 = __main_leds[0+:1];
assign LED1 = __main_leds[1+:1];
assign LED2 = __main_leds[2+:1];
assign LED3 = __main_leds[3+:1];
assign LED4 = __main_leds[4+:1];

// VGA

`ifdef VGA

assign PMOD0_1  = __main_out_vga_r[2+:1];
assign PMOD0_2  = __main_out_vga_r[3+:1];
assign PMOD0_3  = __main_out_vga_r[4+:1];
assign PMOD0_4  = __main_out_vga_r[5+:1];

assign PMOD0_7  = __main_out_vga_b[2+:1];
assign PMOD0_8  = __main_out_vga_b[3+:1];
assign PMOD0_9  = __main_out_vga_b[4+:1];
assign PMOD0_10 = __main_out_vga_b[5+:1];

assign PMOD1_1  = __main_out_vga_g[2+:1];
assign PMOD1_2  = __main_out_vga_g[3+:1];
assign PMOD1_3  = __main_out_vga_g[4+:1];
assign PMOD1_4  = __main_out_vga_g[5+:1];

assign PMOD1_7  = __main_out_vga_hs;
assign PMOD1_8  = __main_out_vga_vs;

`endif

endmodule
{
  "name": "crosslink_nx_evn",
  "variants": [
    {
      "name": "configurable",
      "framework" : "crosslink_nx_evn.v",
      "pins": [
        {"set"    : "basic"},
        {"set"    : "vga",  "define" : "VGA=1"}
      ],
      "builders": [
      {
        "builder" : "edalize",
        "description": "Build using Edalize",
        "tool": "radiant",
        "tool_options": [
          {
              "part": "LIFCL-40-9BG400C"
          }
        ],
        "bitstream"  : "impl/build_impl.bit",
        "constraints": [{"name": "crosslink_nx_evn.pdc", "file_type": "PDC"}],
        "program": [{"cmd" : "openFPGALoader", "args" : "impl/build_impl.bit"}]
      },
      {
        "builder" : "shell",
        "command" : "crosslink_nx_evn.sh",
        "description": "Custom shell scripts using lattice radiant"
      }
    ]
  }
  ],
  "pins": {
    "basic": [
        {
          "name": "leds",
          "type": "uint5",
          "io": "output"
        }
      ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ]
  }
}
`define MOJO 1
$$MOJO=1
$$HARDWARE = 1
$$NUM_LEDS = 8
$$NUM_BTNS = 1
$$color_depth = 6
$$color_max   = 63

module top(
    input  rst_n,
    input  cclk,
    output [7:0] leds,
    output spi_miso,
    input  spi_ss,
    input  spi_mosi,
    input  spi_sck,
    output [3:0] spi_channel,
    input  avr_tx,
    output avr_rx,
    input  avr_rx_busy,
    // SDRAM
    output sdram_clk,
    output sdram_cle,
    output sdram_dqm,
    output sdram_cs,
    output sdram_we,
    output sdram_cas,
    output sdram_ras,
    output [1:0] sdram_ba,
    output [12:0] sdram_a,
    inout [7:0] sdram_dq,
    // HDMI
    output [3:0] gpdi_dp,
    output [3:0] gpdi_dn,
    input clk
    );

wire [7:0]  __main_out_leds;

wire        __main_spi_miso;
wire        __main_out_avr_rx;
wire [3:0]  __main_out_spi_channel;

wire        __main_out_sdram_clk;
wire        __main_out_sdram_cle;
wire        __main_out_sdram_dqm;
wire        __main_out_sdram_cs;
wire        __main_out_sdram_we;
wire        __main_out_sdram_cas;
wire        __main_out_sdram_ras;
wire [1:0]  __main_out_sdram_ba;
wire [12:0] __main_out_sdram_a;
wire [3:0]  __main_out_hdmi1_tmds;
wire [3:0]  __main_out_hdmi1_tmdsb;

wire run_main;
assign run_main = 1'b1;

M_main __main(
  .reset(~rst_n),
  .in_run(run_main),
  .out_leds(__main_out_leds),
`ifdef SDRAM
  .inout_sdram_dq(sdram_dq),
  .out_sdram_clk(__main_out_sdram_clk),
  .out_sdram_cle(__main_out_sdram_cle),
  .out_sdram_dqm(__main_out_sdram_dqm),
  .out_sdram_cs(__main_out_sdram_cs),
  .out_sdram_we(__main_out_sdram_we),
  .out_sdram_cas(__main_out_sdram_cas),
  .out_sdram_ras(__main_out_sdram_ras),
  .out_sdram_ba(__main_out_sdram_ba),
  .out_sdram_a(__main_out_sdram_a),
`endif  
`ifdef HDMI
  .out_gpdi_dp  (__main_out_gpdi_dp),
  .out_gpdi_dn  (__main_out_gpdi_dn),
`endif
  .clock(clk)
);

assign spi_miso    = 1'bz;
assign avr_rx      = 1'bz;
assign spi_channel = 4'bzzzz;

assign leds        = __main_out_leds;
  
`ifdef SDRAM
assign sdram_clk     = __main_out_sdram_clk;
assign sdram_cle     = __main_out_sdram_cle;
assign sdram_dqm     = __main_out_sdram_dqm;
assign sdram_cs      = __main_out_sdram_cs;
assign sdram_we      = __main_out_sdram_we;
assign sdram_cas     = __main_out_sdram_cas;
assign sdram_ras     = __main_out_sdram_ras;
assign sdram_ba      = __main_out_sdram_ba;
assign sdram_a       = __main_out_sdram_a;
`else
assign sdram_clk     = 1'bz;
assign sdram_cle     = 1'bz;
assign sdram_dqm     = 1'bz;
assign sdram_cs      = 1'bz;
assign sdram_we      = 1'bz;
assign sdram_cas     = 1'bz;
assign sdram_ras     = 1'bz;
assign sdram_ba      = 2'bzz;
assign sdram_a       = 12'bzzzzzzzzzzzz;
`endif
  
`ifdef HDMI
assign gpdi_dp       = __main_out_gpdi_dp;
assign gpdi_dn       = __main_out_gpdi_dn;
`else
assign gpdi_dp       = 4'bzzzz;
assign gpdi_dn       = 4'bzzzz;
`endif
  
endmodule
NET "clk" TNM_NET = clk;
TIMESPEC TS_clk = PERIOD "clk" 50 MHz HIGH 50%;

NET "clk" LOC = P56 | IOSTANDARD = LVTTL;
NET "rst_n" LOC = P38 | IOSTANDARD = LVTTL;

NET "cclk" LOC = P70 | IOSTANDARD = LVTTL;

NET "leds<0>" LOC = P134 | IOSTANDARD = LVTTL;
NET "leds<1>" LOC = P133 | IOSTANDARD = LVTTL;
NET "leds<2>" LOC = P132 | IOSTANDARD = LVTTL;
NET "leds<3>" LOC = P131 | IOSTANDARD = LVTTL;
NET "leds<4>" LOC = P127 | IOSTANDARD = LVTTL;
NET "leds<5>" LOC = P126 | IOSTANDARD = LVTTL;
NET "leds<6>" LOC = P124 | IOSTANDARD = LVTTL;
NET "leds<7>" LOC = P123 | IOSTANDARD = LVTTL;

NET "spi_mosi" LOC = P44 | IOSTANDARD = LVTTL;
NET "spi_miso" LOC = P45 | IOSTANDARD = LVTTL;
NET "spi_ss" LOC = P48 | IOSTANDARD = LVTTL;
NET "spi_sck" LOC = P43 | IOSTANDARD = LVTTL;
NET "spi_channel<0>" LOC = P46 | IOSTANDARD = LVTTL;
NET "spi_channel<1>" LOC = P61 | IOSTANDARD = LVTTL;
NET "spi_channel<2>" LOC = P62 | IOSTANDARD = LVTTL;
NET "spi_channel<3>" LOC = P65 | IOSTANDARD = LVTTL;

NET "avr_tx" LOC = P55 | IOSTANDARD = LVTTL;
NET "avr_rx" LOC = P59 | IOSTANDARD = LVTTL;
NET "avr_rx_busy" LOC = P39 | IOSTANDARD = LVTTL;

NET "sdram_clk" LOC = P29 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_cle" LOC = P30 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dqm" LOC = P74 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_cs" LOC = P84 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_we" LOC = P81 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_cas" LOC = P82 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_ras" LOC = P83 | IOSTANDARD = LVTTL | SLEW = FAST;

NET "sdram_ba<0>" LOC = P85 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_ba<1>" LOC = P87 | IOSTANDARD = LVTTL | SLEW = FAST;

NET "sdram_a<0>" LOC = P101 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<1>" LOC = P102 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<2>" LOC = P104 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<3>" LOC = P105 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<4>" LOC = P5 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<5>" LOC = P6 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<6>" LOC = P7 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<7>" LOC = P8 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<8>" LOC = P9 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<9>" LOC = P10 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<10>" LOC = P88 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<11>" LOC = P27 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_a<12>" LOC = P26 | IOSTANDARD = LVTTL | SLEW = FAST;

NET "sdram_dq<0>" LOC = P75 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<1>" LOC = P78 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<2>" LOC = P79 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<3>" LOC = P80 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<4>" LOC = P34 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<5>" LOC = P35 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<6>" LOC = P40 | IOSTANDARD = LVTTL | SLEW = FAST;
NET "sdram_dq<7>" LOC = P41 | IOSTANDARD = LVTTL | SLEW = FAST;

NET "gpdi_dp(3)"  LOC = "P144" |IOSTANDARD = TMDS_33 | CLOCK_DEDICATED_ROUTE = FALSE ; # Clock	
NET "gpdi_dn(3)"  LOC = "P143" |IOSTANDARD = TMDS_33 | CLOCK_DEDICATED_ROUTE = FALSE ;
NET "gpdi_dp(2)"  LOC = "P138" |IOSTANDARD = TMDS_33 ; # Red 	
NET "gpdi_dn(2)"  LOC = "P137" |IOSTANDARD = TMDS_33 ;
NET "gpdi_dp(1)"  LOC = "P140" |IOSTANDARD = TMDS_33 ; # Green	
NET "gpdi_dn(1)"  LOC = "P139" |IOSTANDARD = TMDS_33 ;
NET "gpdi_dp(0)"  LOC = "P142" |IOSTANDARD = TMDS_33 ; # Blue
NET "gpdi_dn(0)"  LOC = "P141" |IOSTANDARD = TMDS_33 ;
{
  "name": "mojov3",
  "variants": [
    {
      "name": "configurable",
      "framework" : "mojov3.v",
      "pins": [
        {"set"    : "basic"}
      ],
      "builders": [
      {
        "builder" : "edalize",
        "description": "Build using Edalize",
        "tool": "ise",
        "tool_options": [
          {
            "family": "spartan6",
            "device": "xc6slx9",
            "package": "tqg144",
            "speed"  : -2
          }
        ],
        "toplevel" : "top",
        "bitstream"  : "top.bin",
        "constraints": [
          {"name": "mojov3.ucf", "file_type": "UCF"}
        ],
        "program": [
          {"cmd" : "promgen", "args" : "-u 0 top.bit -p bin -spi -w"},
          {"cmd" : "printf", "args" : "\"\\n\\nThe programming file has been generated in BUILD_mojov3/top.bin, please use Mojo Loader to program your board\\n\\n\""},
          {"cmd" : "mojo-loader", "args" : "-b top.bin"}
        ]
      }
      ]
    }
  ],
  "pins": {
    "basic": [
      {
        "name": "leds",
        "type": "uint8",
        "io"  : "output"
      }
    ]
  }
}
`define ICARUS 1
$$ICARUS      = 1
$$SIMULATION  = 1
$$NUM_LEDS    = 8
$$color_depth = 6
$$color_max   = 63
$$config['bram_wenable_width'] = 'data'
$$config['dualport_bram_wenable0_width'] = 'data'
$$config['dualport_bram_wenable1_width'] = 'data'

`timescale 1ns / 1ps

module top;

reg clk;
reg rst_n;

wire [7:0] __main_leds;

`ifdef VGA  
wire __main_video_clock;
wire __main_video_hs;
wire __main_video_vs;
wire [5:0] __main_video_r;
wire [5:0] __main_video_g;
wire [5:0] __main_video_b;
`endif

`ifdef UART
wire __main_uart_tx;
wire __main_uart_rx = 0;
`endif

`ifdef HDMI
wire [3:0] __main_out_gpdi_dp;
wire [3:0] __main_out_gpdi_dn;
`endif

initial begin
  clk = 1'b0;
  rst_n = 1'b0;
  $display("icarus framework started");
  $dumpfile("icarus.fst");
`ifdef DUMP_TOP_ONLY
  $dumpvars(1,top); // dump only top (faster and smaller)
`else
  $dumpvars(0,top); // dump all (for full debugging)
`endif
`ifdef CLOCK_25MHz
  // generate a 25 MHz clock
  repeat(4) #20 clk = ~clk; 
  rst_n = 1'b1;
  forever #20 clk = ~clk;
`else
  // generate a 100 MHz clock
  repeat(4) #5 clk = ~clk; 
  rst_n = 1'b1;
  forever #5 clk = ~clk;   
`endif
end

reg ready = 0;
reg [3:0] RST_d;
reg [3:0] RST_q;

always @* begin
  RST_d = RST_q >> 1;
end

always @(posedge clk) begin
  if (ready) begin
    RST_q <= RST_d;
  end else begin
    ready <= 1;
    RST_q <= 4'b1111;
  end
end

wire run_main;
assign run_main = 1'b1;
wire done_main;

M_main __main(
  .clock(clk),
  .reset(RST_d[0]),
  .out_leds(__main_leds),
`ifdef VGA  
  .out_video_clock(__main_video_clock),
  .out_video_r(__main_video_r),
  .out_video_g(__main_video_g),
  .out_video_b(__main_video_b),
  .out_video_hs(__main_video_hs),
  .out_video_vs(__main_video_vs),  
`endif  
`ifdef UART
  .out_uart_tx(__main_uart_tx),
  .in_uart_rx(__main_uart_rx),
`endif  
`ifdef HDMI
  .out_gpdi_dp  (__main_out_gpdi_dp),
  .out_gpdi_dn  (__main_out_gpdi_dn),
`endif  
  .in_run(run_main),
  .out_done(done_main)
);

always @* begin
  if (done_main && !RST_d[0]) $finish;
end

endmodule

#!/bin/bash

case "$(uname -s)" in
MINGW*|CYGWIN*) 
SILICE_DIR=`cygpath $SILICE_DIR`
BUILD_DIR=`cygpath $BUILD_DIR`
FRAMEWORKS_DIR=`cygpath $FRAMEWORKS_DIR`
FRAMEWORK_FILE=`cygpath $FRAMEWORK_FILE`
BOARD_DIR=`cygpath $BOARD_DIR`
;;
*)
esac

echo "build script: SILICE_DIR     = $SILICE_DIR"
echo "build script: BUILD_DIR      = $BUILD_DIR"
echo "build script: BOARD_DIR      = $BOARD_DIR"
echo "build script: FRAMEWORKS_DIR = $FRAMEWORKS_DIR"
echo "build script: FRAMEWORK_FILE = $FRAMEWORK_FILE"

export PATH=$PATH:$SILICE_DIR:$SILICE_DIR/../tools/fpga-binutils/mingw64/bin/
case "$(uname -s)" in
MINGW*)
export PYTHONHOME=/mingw64/bin
export PYTHONPATH=/mingw64/lib/python3.8/
export QT_QPA_PLATFORM_PLUGIN_PATH=/mingw64/share/qt5/plugins
;;
*)
esac

cd $BUILD_DIR

rm build* icarus.fst icarus.fst.hier

silice --frameworks_dir $FRAMEWORKS_DIR -f $FRAMEWORK_FILE -o build.v $1 "${@:2}"

iverilog -o build build.v
vvp build -fst

gtkwave icarus.fst
{
  "name": "icarus",
  "variants": [
    {
      "name"      : "configurable",
      "framework" : "icarus.v",
      "pins"      : [ 
        {"set"    : "basic"},
        {"set"    : "vga", "define"  : "VGA=1"},
        {"set"    : "hdmi", "define" : "HDMI=1"},
        {"set"    : "uart", "define" : "UART=1"},
        {"set"    : "top_only", "define" : "DUMP_TOP_ONLY=1"}
      ],
      "builders": [
        {
          "builder" : "shell",
          "command" : "icarus.sh",
          "description": "Simulates with icarus and opens gtkwave for visualization"
        }
      ]
    }
  ],
  "pins": {
    "basic": [
        {
          "name": "leds",
          "type": "uint8",
          "io": "output"
        }
    ],
    "uart": [
      {
        "name": "uart_tx",
        "type": "uint1",
        "io"  : "output"
      },
      {
        "name": "uart_rx",
        "type": "uint1",
        "io"  : "input"
      }
    ],
    "vga": [
      {
        "name": "vga_hs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_vs",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "vga_r",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_g",
        "type": "uint6",
        "io": "output"
      },
      {
        "name": "vga_b",
        "type": "uint6",
        "io": "output"
      }
    ],
    "hdmi": [
      {
        "name": "gpdi_dq",
        "type": "uint1",
        "io": "output"
      },
      {
        "name": "gpdi_dn",
        "type": "uint1",
        "io": "output"
      }
    ]
  }
}
