Need help from a MinGW user Guys,
I found a nifty program on the web that would help me out tremendously by generating VHDL RTL ROM models for simulation. Unfortunately, it inserts (unnecessary) references to Xilinx libraries, and fails to implement the enabled case correctly. I have corrected the flaws in the source, but my copy of minGW is failing to compile the file.
I've also tried compiling it under FreeBSD, and the gcc there complains as well. I'm not a c++ programmer, so I don't know where to begin. I may just rewrite the application in C, but I'm hoping someone here can help me out.
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <math.h>
#include <iostream>
using namespace std;
#define MAX_ROM_SIZE 0x4000
int main(int argc, char* argv[])
{
cerr << "romgen by MikeJ version 3.00\n";
// read file
string buffer;
FILE *fin;
if(argc < 5)
{
cerr << "\nUsage: romgen <input file> <entity name> <number of address bits>\n";
cerr << " <format> {registered} {enable}\n";
cerr << "\n";
cerr << "Now uses bit_vector generics for compatibilty with Xilinx UniSim library\n";
cerr << "\n";
cerr << "for the format paramater use :\n";
cerr << " a - rtl model rom array \n";
cerr << " c - rtl model case statement \n";
cerr << " b - Xilinx block ram4 (registered output always)\n";
cerr << " l - Xilinx block ram16 (registered output always)\n";
cerr << " d - Xilinx distributed ram [not supported yet]\n";
cerr << "\n";
cerr << "for the registered paramater (optional) use :\n";
cerr << " r - registered output (combinatorial otherwise) \n";
cerr << "\n";
cerr << "for the enable paramater (optional) use :\n";
cerr << " e - clock enable generated \n";
cerr << "\n";
cerr << "note, generated roms are always 8 bits wide\n";
cerr << " max 12 address bits for block ram4s\n";
cerr << " max 14 address bits for block ram16s\n";
cerr << "for example romgen fred.bin fred_rom 12 c r\n\n";
return -1;
}
fin = fopen(argv[1],"rb");
if (fin == NULL) {
cerr << "ERROR : Could not open input file " << argv[1] <<"\n";
return -1;
}
char rom_type = 0;
char option_1 = 0;
char option_2 = 0;
sscanf(argv[4],"%c",&rom_type);
if (argc > 5) sscanf(argv[5],"%c",&option_1);
if (argc > 6) sscanf(argv[6],"%c",&option_2);
bool format_case = false;
bool format_array = false;
bool format_block = false;
bool format_dist = false;
bool format_clock = false;
bool format_ram16 = false;
bool format_ena = false;
cerr << "INFO : creating entity : " << argv[2] << "\n";
if (option_1 != 0) {
if ((option_1 == 'r') || (option_1 == 'R'))
format_clock = true;
else if ((option_1 == 'e') || (option_1 == 'E'))
format_ena = true;
else {
cerr << "ERROR : output option not supported\n";
return -1;
}
}
// lazy ...
if (option_2 != 0) {
if ((option_2 == 'r') || (option_2 == 'R'))
format_clock = true;
else if ((option_2 == 'e') || (option_2 == 'E'))
format_ena = true;
else {
cerr << "ERROR : output option not supported\n";
return -1;
}
}
if ((rom_type == 'c') || (rom_type == 'C')) {
cerr << "INFO : rtl model, case statement \n"; format_case = true; }
else if ((rom_type == 'a') || (rom_type == 'A')) {
cerr << "INFO : rtl model, rom array \n"; format_array = true; }
else if ((rom_type == 'b') || (rom_type == 'B')) {
cerr << "INFO : block4 ram, registered \n"; format_block = true; format_clock = true; }
else if ((rom_type == 'l') || (rom_type == 'L')) {
cerr << "INFO : block16 ram, registered \n"; format_block = true; format_clock = true; format_ram16 = true; }
//else if ((rom_type == 'd') || (rom_type == 'D')) {
// cerr << "INFO : distributed ram, combinatorial; \n"; format_dist = true; }
else {
cerr << "ERROR : format not supported\n";
return -1;
}
if (format_clock == true)
cerr << "INFO : registered output\n\n";
else
cerr << "INFO : combinatorial output\n\n";
// calc number of address bits required
int addr_bits;
int max_addr_bits = 16;
int rom_inits = 16;
if (format_block == true) {
if (format_ram16 == true) {
max_addr_bits = 14;
rom_inits = 64;
}
else
max_addr_bits = 12;
}
sscanf(argv[3],"%d",&addr_bits);
if (addr_bits < 1 || addr_bits > max_addr_bits) {
cerr << "ERROR : illegal rom size, number of address bits must be between 1 and " << max_addr_bits << "\n";
return -1;
}
// ram b16s
// for 14 bits use ram_b16_s1 x data_width
// for 13 bits use ram_b16_s2 x data_width/2
// for 12 bits use ram_b16_s4 x data_width/4
// for<=11 bits use ram_b16_s8 x data_width/8
// ram b4s
// for 12 bits use ram_b4_s1 x data_width
// for 11 bits use ram_b4_s2 x data_width/2
// for 10 bits use ram_b4_s4 x data_width/4
// for <=9 bits use ram_b4_s8 x data_width/8
int rom_size = (int) pow(2,addr_bits);
int number_of_block_rams = 1;
int block_ram_width = 8;
int block_ram_pwidth = 0;
int block_ram_abits = 9;
if (format_ram16 == true) {
block_ram_abits = 11; // default
block_ram_pwidth = 1;
// ram16s
switch (addr_bits) {
case 14 : number_of_block_rams = 8; block_ram_width = 1; block_ram_pwidth = 0; block_ram_abits = 14; break;
case 13 : number_of_block_rams = 4; block_ram_width = 2; block_ram_pwidth = 0; block_ram_abits = 13; break;
case 12 : number_of_block_rams = 2; block_ram_width = 4; block_ram_pwidth = 0; block_ram_abits = 12; break;
default : ;
}
}
else {
// ram4s
switch (addr_bits) {
case 12 : number_of_block_rams = 8; block_ram_width = 1; block_ram_abits = 12; break;
case 11 : number_of_block_rams = 4; block_ram_width = 2; block_ram_abits = 11; break;
case 10 : number_of_block_rams = 2; block_ram_width = 4; block_ram_abits = 10; break;
default : ;
}
}
//printf("block ram w : %d ",block_ram_width);
//printf("block ram n : %d ",number_of_block_rams);
// process
int mem[MAX_ROM_SIZE];
string line;
int i,j,k;
int addr = 0;
int offset = 0;
int mask = 0;
unsigned int data = 0;
// clear mem
for (i = 0; i < MAX_ROM_SIZE; i++) mem[i] = 0;
// process file
data = getc(fin);
while (!feof(fin) && (addr < rom_size)) {
if (addr >= MAX_ROM_SIZE) {
cerr << "ERROR : file too large\n";
return -1;
}
mem[addr] = data;
// debug
//if (addr % 16 == 0) printf("%04x : ",addr);
//printf("%02x ",data);
//if (addr % 16 == 15) printf("\n");
// end debug
addr ++;
data = getc(fin);
}
fclose(fin);
printf("-- generated with romgen v3.0 by MikeJ\n");
printf("library ieee;\n");
printf(" use ieee.std_logic_1164.all;\n");
printf(" use ieee.std_logic_unsigned.all;\n");
printf(" use ieee.numeric_std.all;\n");
printf("\n");
// printf("library UNISIM;\n");
// printf(" use UNISIM.Vcomponents.all;\n");
// printf("\n");
printf("entity %s is\n",argv[2]);
printf(" port (\n");
if (format_clock == true) printf(" CLK : in std_logic;\n");
if (format_ena == true) printf(" ENA : in std_logic;\n");
printf(" ADDR : in std_logic_vector(%d downto 0);\n",addr_bits - 1);
printf(" DATA : out std_logic_vector(7 downto 0)\n");
printf(" );\n");
printf("end;\n");
printf("\n");
printf("architecture RTL of %s is\n",argv[2]);
printf("\n");
// if blockram
//{{{
if (format_block == true) {
printf(" function romgen_str2bv (str : string) return bit_vector is\n");
printf(" variable result : bit_vector (str'length*4-1 downto 0);\n");
printf(" begin\n");
printf(" for i in 0 to str'length-1 loop\n");
printf(" case str(str'high-i) is\n");
for (i = 0; i<16; i++)
printf(" when '%01X' => result(i*4+3 downto i*4) := x\042%01X\042;\n",i,i);
printf(" when others => null;\n");
printf(" end case;\n");
printf(" end loop;\n");
printf(" return result;\n");
printf(" end romgen_str2bv;\n");
printf("\n");
// xilinx block ram component
if (block_ram_pwidth != 0) {
for (i = 0; i< 8; i++)
printf(" attribute INITP_%02X : string;\n",i);
printf("\n");
}
for (i = 0; i< rom_inits; i++)
printf(" attribute INIT_%02X : string;\n",i);
printf("\n");
if (format_ram16 == true)
printf(" component RAMB16_S%d\n",block_ram_width + block_ram_pwidth);
else
printf(" component RAMB4_S%d\n",block_ram_width);
printf(" --pragma translate_off\n");
printf(" generic (\n");
if (block_ram_pwidth != 0) {
for (i = 0; i< 8; i++) {
printf(" INITP_%02X : bit_vector (255 downto 0) := x\0420000000000000000000000000000000000000000000000000000000000000000\042",i);
printf(";\n");
}
printf("\n");
}
for (i = 0; i< rom_inits; i++) {
printf(" INIT_%02X : bit_vector (255 downto 0) := x\0420000000000000000000000000000000000000000000000000000000000000000\042",i);
if (i< (rom_inits - 1)) printf(";");
printf("\n");
}
printf(" );\n");
printf(" --pragma translate_on\n");
printf(" port (\n");
printf(" DO : out std_logic_vector (%d downto 0);\n",block_ram_width -1);
if (block_ram_pwidth != 0)
printf(" DOP : out std_logic_vector (%d downto 0);\n",block_ram_pwidth -1);
printf(" ADDR : in std_logic_vector (%d downto 0);\n",block_ram_abits -1);
printf(" CLK : in std_logic;\n");
printf(" DI : in std_logic_vector (%d downto 0);\n",block_ram_width -1);
if (block_ram_pwidth != 0)
printf(" DIP : in std_logic_vector (%d downto 0);\n",block_ram_pwidth -1);
printf(" EN : in std_logic;\n");
if (format_ram16 == true)
printf(" SSR : in std_logic;\n");
else
printf(" RST : in std_logic;\n");
printf(" WE : in std_logic \n");
printf(" );\n");
printf(" end component;\n");
printf("\n");
printf(" signal rom_addr : std_logic_vector(%d downto 0);\n",block_ram_abits - 1);
printf("\n");
}
//}}}
//{{{
if (format_array == true) {
printf("\n");
printf(" type ROM_ARRAY is array(0 to %d) of std_logic_vector(7 downto 0);\n",rom_size - 1);
printf(" constant ROM : ROM_ARRAY := (\n");
for (i = 0; i < rom_size; i ++ ) {
if (i % 8 == 0) printf(" ");
printf("x\042%02X\042",mem[i]);
if (i < (rom_size - 1)) printf(",");
if (i == (rom_size - 1)) printf(" ");
if (i % 8 == 7) printf(" -- 0x%04X\n",i - 7);
}
printf(" );\n");
printf("\n");
} // end array
//}}}
//{{{
if (format_case == true) {
printf(" signal rom_addr : std_logic_vector(11 downto 0);\n");
printf("\n");
}
//}}}
printf("begin\n");
printf("\n");
//
if ((format_block == true) || (format_case == true)) {
printf(" p_addr : process(ADDR)\n");
printf(" begin\n");
printf(" rom_addr <= (others => '0');\n");
printf(" rom_addr(%d downto 0) <= ADDR;\n",addr_bits - 1);
printf(" end process;\n");
printf("\n");
}
//
//{{{
if (format_block == true) {
for (k = 0; k < number_of_block_rams; k ++){
printf(" rom%d : if true generate\n",k);
for (j = 0; j < rom_inits; j++) {
printf(" attribute INIT_%02X of inst : label is \042",j);
switch (block_ram_width) {
case 1 : // width 1
mask = 0x1 << (k);
for (i = 0; i < 256; i+=8) {
data = ((mem[(j*256) + (255 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (254 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (253 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (252 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (251 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (250 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (249 - i)] & mask) >> k);
data <<= 1;
data += ((mem[(j*256) + (248 - i)] & mask) >> k);
printf("%02X",data);
}
break;
case 2 : // width 2
mask = 0x3 << (k * 2);
for (i = 0; i < 128; i+=4) {
data = ((mem[(j*128) + (127 - i)] & mask) >> k * 2);
data <<= 2;
data += ((mem[(j*128) + (126 - i)] & mask) >> k * 2);
data <<= 2;
data += ((mem[(j*128) + (125 - i)] & mask) >> k * 2);
data <<= 2;
data += ((mem[(j*128) + (124 - i)] & mask) >> k * 2);
printf("%02X",data);
}
break;
case 4 : // width 4
mask = 0xF << (k * 4);
for (i = 0; i < 64; i+=2) {
data = ((mem[(j*64) + (63 - i)] & mask) >> k * 4);
data <<= 4;
data += ((mem[(j*64) + (62 - i)] & mask) >> k * 4);
printf("%02X",data);
}
break;
case 8 : // width 8
for (i = 0; i < 32; i++) {
data = ((mem[(j*32) + (31 - i)]));
printf("%02X",data);
}
break;
} // end switch
printf("\042;\n");
}
printf(" begin\n");
if (format_ram16 == true)
printf(" inst : RAMB16_S%d\n",block_ram_width + block_ram_pwidth);
else
printf(" inst : RAMB4_S%d\n",block_ram_width);
printf(" --pragma translate_off\n");
printf(" generic map (\n");
if (block_ram_pwidth != 0) {
for (i = 0; i< 8; i++) {
printf(" INITP_%02X => x\0420000000000000000000000000000000000000000000000000000000000000000\042",i);
printf(",\n");
}
printf("\n");
}
for (i = 0; i< rom_inits; i++) {
printf(" INIT_%02X => romgen_str2bv(inst'INIT_%02X)",i,i);
if (i< (rom_inits - 1)) printf(",");
printf("\n");
}
printf(" )\n");
printf(" --pragma translate_on\n");
printf(" port map (\n");
printf(" DO => DATA(%d downto %d),\n",((k+1) * block_ram_width)-1,k*block_ram_width);
if (block_ram_pwidth != 0)
printf(" DOP => open,\n");
printf(" ADDR => rom_addr,\n");
printf(" CLK => CLK,\n");
printf(" DI => \042");
for (i = 0; i < block_ram_width -1; i++) printf("0");
printf("0\042,\n");
if (block_ram_pwidth != 0) {
printf(" DIP => \042");
for (i = 0; i < block_ram_pwidth -1; i++) printf("0");
printf("0\042,\n");
}
if (format_ena == true)
printf(" EN => ENA,\n");
else
printf(" EN => '1',\n");
//
if (format_ram16 == true)
printf(" SSR => '0',\n");
else
printf(" RST => '0',\n");
printf(" WE => '0'\n");
printf(" );\n");
printf(" end generate;\n");
}
} // end block ram
//}}}
//{{{
if (format_array == true) {
if (format_clock == true)
printf(" p_rom : process\n");
else
printf(" p_rom : process(ADDR)\n");
printf(" begin\n");
if (format_clock == true)
printf(" wait until rising_edge(CLK);\n");
if (format_ena == true){
printf(" DATA <= x\"00\"\n");
printf(" if (ENA = '1') then\n "); }
printf(" DATA <= ROM(to_integer(unsigned(ADDR)));\n");
if (format_ena == true)
printf(" end if;\n");
printf(" end process;\n");
//}}}
} // end array
//{{{
if (format_case == true) {
if (format_clock == true)
printf(" p_rom : process\n");
else
printf(" p_rom : process(rom_addr)\n");
printf(" begin\n");
if (format_clock == true)
printf(" wait until rising_edge(CLK);\n");
if (format_ena == true){
printf(" DATA <= x\"00\"\n");
printf(" if (ENA = '1') then\n"); }
printf(" DATA <= (others => '0');\n");
printf(" case rom_addr is\n");
for (i = 0; i < rom_size; i ++ ) {
printf(" when x\042%03X\042 => DATA <= x\042%02X\042;\n",i,mem[i]);
}
printf(" when others => DATA <= (others => '0');\n");
printf(" end case;\n");
if (format_ena == true)
printf(" end if;\n");
printf(" end process;\n");
//}}}
} // end case
printf("end RTL;\n");
return 0;
}
Note, I have already made the corrections in this version. Now I just need to figure out how to compile it.
Thanks!
BillW- 08-10-2006
Check you mail.
radarman- 08-10-2006
Sweet! Thanks :)
BTW - I was able to get pv2ass modified, and it now generates correct code for DBNZ. I wrote a small program that does a RAM check using the new instructions:
; BootROM core
.INCLUDE "HW_DEFINES.INC"
.INCLUDE "GLOBALS.INC"
; README!
; This bootrom assumes that auto-indexing is enabled in the CPU core
; Auto-indexing is implied when an odd register is used with an indexed
; addressing mode, such as STX R5, LDO R3, and results in the next lower pair
; being used, followed by an increment. The result is that STX R5 is
; equivalent to STX R4 ; UPP R4
; This bootrom makes use of instructions which are NOP's on the PV2 version of
; the processor. Specifically, it makes use of the DBNZ, SMSK, and GMSK
; opcodes
.ORG $0000
; Initialize system memory for self--*test*-('")
DISABLE_INTS: CLR R0
STA R0, HW_TIMER_CONFIG ; Disable HW Timer
SMSK ; Clear interrupt mask to disable other hardware
MEM_TEST_S1: T0X R6
T0X R7 ; Clear R7:R6 as the error counter
CLP PSR_GP4 ; Clear GP4 to indicate cycle 1
LDI R0,#$A5 ; Initialize R0 to 0xA5 for the first cycle
BNGP4 MEM_TEST_ENT
MEM_TEST_S2: STP PSR_GP4 ; Set GP4 to indicate cycle 2
LDI R0,#$5A ; Initialize R0 to 0x5A for the second cycle
MEM_TEST_ENT: T0X R1 ; Copy -*test*-('") vector to R1 for safe-keeping
LDI R4,#$00 ; Start at the first location of BRAM
LDI R5,#$00 ; This should match RAM_Start_Addr in the VHDL
LDI R2,#$FF ; Scan all defined R/W memory
LDI R3,#$7F ; This should match RAM_Size
MEM_WR_LOOP: STX R5 ; Use auto-increment on R5:R4
DBNZ R2,MEM_WR_LOOP
DBNZ R3,MEM_WR_LOOP
LDI R4,#$00
LDI R5,#$00
LDI R2,#$FF ; Scan all defined R/W memory
LDI R3,#$7F ; This should match RAM_Size
MEM_RD_LOOP: LDX R5
CMP R1 ; Compare R0 (recently loaded) with R1 (original data)
BRZ MEM_OK1
UPP R6 ; If a mis-compare occurs, increment the error counter
MEM_OK1: DBNZ R2, MEM_RD_LOOP
DBNZ R3, MEM_RD_LOOP
BNGP4 MEM_TEST_S2
VI_EXIT: JMP MAIN
This code will fail on a PV2, for obvious reasons...
Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.