Forum: FPGA, VHDL & Co. Hilfsprogramm zur ROM-Erzeugung geschrieben


von Rüdiger K. (sleipnir)


Angehängte Dateien:

Lesenswert?

Da die Erzeugung von ROM-Beschreibungen in 
Hardware-Beschreibungssprachen aus Binärdateien etwas schwierig ist 
(Beispiel: 
https://www.mikrocontroller.net/articles/Retrocomputing_auf_FPGA#.28P.29ROM-Images), 
habe ich ein Hilfsprogramm geschrieben, welche diese Aufgabe 
automatisiert. Es ist bewußt so gehalten, das es z.B. nach einem 
Assembler- oder Compilerlauf als weiteren Schritt aufgerufen werden 
kann.

Momentan werden nur 8-Bit-ROM's und VHDL-Exporte unterstützt, aber es 
kann zwischen getakteten und nicht-getakteten Implementierungen mit 
wahlweisem "output enable"-Eingang gewählt werden.

Weiterhin werden mehrere Quellen unterstützt, wobei die Quellenangabe 
optional einen Byte-Offset, eine Byte-Länge und die Zieladresse im ROM 
haben kann. Das Beispiel wurde mit dem Aufruf
1
bin/romGenerator -outputFile=ROM.vhdl -defaultValue=0xFF -sources=test200Bytes.bin::length10::offset2,test200Bytes.bin::length5::mapTo10
erzeugt.
1
-- Address bits:   10
2
-- Data bus bits:   8
3
-- Active clock flank:   FallingEdge
4
-- Output enable type:   LowActive
5
-- Source mapping:
6
--   test200Bytes.bin bytes [0x2, 0xb] -> ROM byte range [0x0, 0x9]
7
--   test200Bytes.bin bytes [0x0, 0x4] -> ROM byte range [0xa, 0xe]
8
9
library ieee;
10
use ieee.std_logic_1164.all;
11
use ieee.numeric_std.all;
12
13
entity ROM is 
14
 port(
15
  Clk_n : in std_logic; --! Clock input (active on the falling edge)
16
  OE_n : in std_logic; --! Output enable input (L-active)
17
  A : in std_logic_vector(9 downto 0); --! Address bus
18
  D : out std_logic_vector(7 downto 0)); --! Data bus
19
end ROM;
20
21
architecture BEHAVIOR of ROM is 
22
 type romtable_t is array(0 to 1023) of std_logic_vector(7 downto 0);
23
 signal Dint : std_logic_vector(7 downto 0);
24
 constant ROMdata : romtable_t := (
25
  0 => x"02", -- test200Bytes.bin bytes [0x2, 0xb] -> ROM byte range [0x0, 0x9]
26
  1 => x"03",
27
  2 => x"04",
28
  3 => x"05",
29
  4 => x"06",
30
  5 => x"07",
31
  6 => x"08",
32
  7 => x"09",
33
  8 => x"0a",
34
  9 => x"0b",
35
  10 => x"00", -- test200Bytes.bin bytes [0x0, 0x4] -> ROM byte range [0xa, 0xe]
36
  11 => x"01",
37
  12 => x"02",
38
  13 => x"03",
39
  14 => x"04",
40
  others => x"ff");
41
42
begin
43
 process (Clk)
44
 begin
45
   if falling_edge(Clk) then
46
    Dint <= ROMdata(to_integer(unsigned(A)));
47
   end if;
48
 end process;
49
50
 D <= Dint when OE_n='0' else (others => 'Z');
51
end BEHAVIOR;

Die Quellen sind unter
https://sourceforge.net/projects/romgenerator/files/romGenerator-1.0.0.tar.gz/download
zu finden.

von Duke Scarring (Gast)


Lesenswert?

Danke Rüdiger.
Wenn man sich mit Softcores beschäftigt, findet man eigentlich bei allen 
CPUs ein entsprechendes Hilfsprogramm.

Duke

von Rüdiger (Gast)


Lesenswert?

Ups... wußte ich noch nicht. Ich wollte mein Minimal-Z80 System in VHDL 
nachbauen und fand gerade für die Weiterentwicklung des Monitorprogramms 
den hier im Wiki beschriebenen Weg recht umständlich.

von Rüdiger K. (sleipnir)


Lesenswert?

Ich habe noch ausführbare Dateien für die x64-Linux-Plattform 
hinzugefügt.
Für Windows muß ich erst einmal einen Cross-Compiler bauen....

von srec_cat (Gast)


Lesenswert?

srec_cat (http://srecord.sourceforge.net/man/man1/srec_cat.html) ist da 
auch ganz praktisch, gerade wenn die Byteorder oder Endianess zusätzlich 
geändert werden soll:
1
−VHdl [ bytes-per-word [ name ]]
2
3
  A VHDL format file will be written. The bytes-per-word defaults to one,
4
  the name defaults to eprom. The etc/x_defs_pack.vhd file in the source
5
  distribution contains an example ROM definitions pack for the
6
  type-independent output. You may need to use the −byte-swap filter to get 
7
  the byte order you want.


Beispielaufruf:
1
srec_cat 2732a.bin -binary -o 2732a.vhd -vhdl

von Rüdiger K. (sleipnir)


Lesenswert?

Danke für die Anregungen - Endianess-Unterstützung werde ich mit 
einbauen, Unterstützung für elf-Dateien wohl auch.

Ich habe es endlich geschafft, eine Win32-Version zu compilieren:
https://sourceforge.net/projects/romgenerator/files/?source=navbar

Könnte mir jemand mit Windows die Funktion bestätigen? Ein Aufruf 
"romGenerator -h" würde schon reichen....

von Fitzebutze (Gast)


Lesenswert?

Nur so als Bemerkung: So ein simples Tool würde ich in Python 
schreiben/portieren, die nötigen Hilfsmittel wie elf.py, intelhex.py, 
usw. sind schnell gefunden und es funktioniert dann 
plattformübergreifend, zudem hat der Endanwender mehr Nutzen davon.

von Fpgakuechle K. (Gast)


Lesenswert?

Rüdiger schrieb:
> fand gerade für die Weiterentwicklung des Monitorprogramms
> den hier im Wiki beschriebenen Weg recht umständlich.

Auf welche Beschreibung beziehst Du dich?

MfG,

von Rüdiger (Gast)


Lesenswert?

Fpga K. schrieb:
> Rüdiger schrieb:
>> fand gerade für die Weiterentwicklung des Monitorprogramms
>> den hier im Wiki beschriebenen Weg recht umständlich.
>
> Auf welche Beschreibung beziehst Du dich?
>
> MfG,

https://www.mikrocontroller.net/articles/Retrocomputing_auf_FPGA#.28P.29ROM-Images

Zum Thema Python: sicher wäre dies auch eine potentielle 
Implementierungssprache. Nicht umsonst hat sie ja auch viele Anhänger.
Allerdings sprechen auch einige Punkte dagegen:
 * Ich bin in Python weniger geübt als in C++
 * Beim Endanwender müßte dann auch ein Python-Interpreter installiert 
sein.
 * Zumindest bei Gentoo habe ich die Erfahrung gemacht, daß die dortigen 
in
   Python geschriebenen Paketverwaltungsprogramme manchmal recht 
empfindlich
   auf eine falsche Python-Version reagieren.

von Fpgakuechle K. (Gast)


Lesenswert?

Rüdiger schrieb:
> Fpga K. schrieb:
>> Rüdiger schrieb:
>>> fand gerade für die Weiterentwicklung des Monitorprogramms
>>> den hier im Wiki beschriebenen Weg recht umständlich.
>>
>> Auf welche Beschreibung beziehst Du dich?
>
> 
https://www.mikrocontroller.net/articles/Retrocomputing_auf_FPGA#.28P.29ROM-Images

OK, ich setz mal an dieser Stelle einen Verweis auf deine Soft. Sinnvoll 
scheint mir auch ein Codeschnipsel der zeigt wie aus HEX VHDL wird. Die
Beschreibung ist umständlich geraten da ich zeigen wollte wie man mit 
(Linux-)Bordmittel (Editor, Basis-tools wie od) Hexfile convertieren 
kann, also ohne Programmiersprache auskommt.

Duke Scarring schrieb:
> Danke Rüdiger.
> Wenn man sich mit Softcores beschäftigt, findet man eigentlich bei allen
> CPUs ein entsprechendes Hilfsprogramm.

Vor der Beschäftigung mit den Xilinx-Hilfstools zur ROM-Initialisierung 
nannte man mich der Haare wegen Winnetou, danach Kojak ....

Insbesonders bei der Benutzung des picoblazes hatt man lernen müßen das
die ROM-Initialisierung per VHDL-array noch die Vorgehensweise mit den 
wenigsten Problemen ist. Allerdings muß man sich dann selbst um die 
Konvertierung Hex->VHDL kümmern. Da kommt dein Tool gerade recht -> 
Danke.

MfG,

von Rüdiger (Gast)


Lesenswert?

Deine Beschreibung ist gut, aber gerade wenn man am Assembler-Quelltext 
herumspielt, hat man irgendwann keine Lust mehr auf die manuelle 
Variante... ;-)

Die Hilfe kann man mit -h aufrufen:
1
./romGenerator-x64-1.0.0 -h
2
./romGenerator-x64-1.0.0 command line switches:
3
 -activeClockFlank     - Specification of the active clock flank ([RisingEdge|FallingEdge|None]) (Currently: None)
4
 -addressBusBitWidth   - Width of the address bus interface in number of bits (range [4, 32]) (Currently: 10)
5
 -dataBusBitWidth      - Width of the data bus interface in number of bits (multiple of 8, range [8, 8]). (Currently: 8)
6
 -defaultValue         - Value to return for unspecified ROM cells. (Currently: 0x0)
7
 -entityName           - Name of the generated entity. (Currently: ROM)
8
 -h                    - Help for all or a single command line arguments.
9
 -outputEnable         - Type of the output enable input ([LowActive|HighActive|None]) (Currently: LowActive)
10
 -outputFile           - Name of the output file.
11
 -outputFormat         - Output format (one of [VHDL] (Currently: VHDL)
12
 -sources              - pathToFile{::mapTo[ROM base byte addr]}{::offset[byte offset in file]}{::length[byte length]},... (e.g. file.bin::offset0x20::length1024::mapTo0x8000,file2.bin)

Will man aus der Datei "prog.bin" die VHDL-Datei eines ungetakteten 
ROM's mit L-aktiven OE (Standard-Vorgabe) und 12 Addressbits generieren 
und dabei die ersten 5 Bytes überspringen, dann lautet der Aufruf
1
 ./romGenerator-x64-1.0.0 -outputFile=rom.vhd -addressBusBitWidth 12 -sources=prog.bin::offset5

Das erzeugt dann die Datei rom.vhd:
1
-- Address bits:   12
2
-- Data bus bits:   8
3
-- Active clock flank:   None
4
-- Output enable type:   LowActive
5
-- Source mapping:
6
--   prog.bin bytes [0x5, 0x11] -> ROM byte range [0x0, 0xc]
7
8
library ieee;
9
use ieee.std_logic_1164.all;
10
use ieee.numeric_std.all;
11
12
entity ROM is 
13
 port(
14
  OE_n : in std_logic; --! Output enable input (L-active)
15
  A : in std_logic_vector(11 downto 0); --! Address bus
16
  D : out std_logic_vector(7 downto 0)); --! Data bus
17
end ROM;
18
19
architecture BEHAVIOR of ROM is 
20
 type romtable_t is array(0 to 4095) of std_logic_vector(7 downto 0);
21
 signal Dint : std_logic_vector(7 downto 0);
22
 constant ROMdata : romtable_t := (
23
  0 => x"05", -- prog.bin bytes [0x5, 0x11] -> ROM byte range [0x0, 0xc]
24
  1 => x"06",
25
  2 => x"07",
26
  3 => x"08",
27
  4 => x"0a",
28
  5 => x"0b",
29
  6 => x"0c",
30
  7 => x"0d",
31
  8 => x"0e",
32
  9 => x"0f",
33
  10 => x"10",
34
  11 => x"11",
35
  12 => x"12",
36
  others => x"00");
37
38
begin
39
 process (A)
40
 begin
41
    Dint <= ROMdata(to_integer(unsigned(A)));
42
 end process;
43
44
 D <= Dint when OE_n='0' else (others => 'Z');
45
end BEHAVIOR;

Wenn die Temperaturen etwas nachlassen werde ich auch die Unterstützung 
für größere Datenbusse mit wählberer Endianess einbauen.

von René D. (Firma: www.dossmatik.de) (dose)


Lesenswert?

> architecture BEHAVIOR of ROM is
>  type romtable_t is array(0 to 4095) of std_logic_vector(7 downto 0);
>  signal Dint : std_logic_vector(7 downto 0);
>  constant ROMdata : romtable_t := (
 x"05", x"06", x"07", x"08", x"0a", x"0b", x"0c", x"0d", x"0e", x"0f" 
x"10",
 x"11", x"12",  others => x"00");
>

Du kannst es auch etwas kürzer Schreiben. Das mach die Datei etwas 
übersichtlicher.

von peter (Gast)


Angehängte Dateien:

Lesenswert?

Es geht auch mit Freebasic wunderbar oder Purebasic.
Ich habe ein Tool für mich enwickelt für :

1Bit : "0" , "1".....
8Bit(Byte) : "01010101" ,"10101010"......
2Hex : x"fd" , x"34".....
4Hex : x"1fe3" , x"1234"......
und Deci : "255" , "111"....

Und Nibble für die Textausgabe auf dem VGA vom DE0, DE1 welches ich 
brauche.

Davor der Kopf für das RAM , Constant usw und den Körper für die 
Ausführung.
Es ist nicht schwer so etwas.


Gruss

von Rüdiger K. (sleipnir)


Lesenswert?

@Rene: das Programm kann auch mehrere Datenblöcke einlesen, etwa für 
Font- oder andere Datenbereiche. Dann braucht man schon die Adressen.

@Peter: Der Gedanke ist ja, diesen Prozeß vollautomatisch in die 
Übersetzung einzubinden, also Compiler/Assembler, VHDL-Generator, ja 
evtl. sogar die FPGA-Übersetzung.

von Rüdiger K. (sleipnir)


Lesenswert?

So, ich habe gerade Version 1.0.1 hochgeladen, welche auch 
Datenbusbreiten > 8 Bit und Angabe der Endianess unterstützt.
https://sourceforge.net/projects/romgenerator/files/?source=navbar

Die Kommandozeilenoptionen:
1
bin/romGenerator-x64-1.0.1 command line switches:
2
 -activeClockFlank         - Specification of the active clock flank ([RisingEdge|FallingEdge|None]) (Currently: None)
3
 -addressBusBitWidth       - Width of the address bus interface in number of bits (range [4, 32]) (Currently: 10)
4
 -dataBusBitWidth          - Width of the data bus interface in number of bits (8, 16, 24, 32, 40, 48, 56, 64 or ) (Currently: 8)
5
 -endianess                - Endianess of the ROM data (either LittleEndian or BigEndian) (Currently: BigEndian)
6
 -entityName               - Name of the generated entity. (Currently: ROM)
7
 -fillEmptyCellsWithOnes   - Fill empty cells with one bits. (Currently: true)
8
 -h                        - Help for all or a single command line arguments.
9
 -outputEnable             - Type of the output enable input ([LowActive|HighActive|None]) (Currently: LowActive)
10
 -outputFile               - Name of the output file.
11
 -outputFormat             - Output format (one of [VHDL]) (Currently: VHDL)
12
 -sources                  - pathToFile{::mapTo[ROM base byte addr]}{::offset[byte offset in file]}{::length[byte length]},... (e.g. file.bin::offset0x20::length1024::mapTo0x8000,file2.bin

Aus einer Testsequenz mit 6 Bytes (01,02,03,04,05,06) macht er bei 32 
Bit Datenbusbreite und BigEndian-ByteOrder mit dem Aufruf
1
bin/romGenerator-x64-1.0.1 -outputFile=test.vhd -sources=test6Byte.bin -dataBusBitWidth=32 -endianess=BigEndian

diese VHDL-Datei:
1
-- Creation time:       Sun Jul 12 17:40:59 2015
2
3
-- Address bits:         10
4
-- Data bus bits:        32
5
-- Endianess:   BigEndian
6
-- Active clock flank:   None
7
-- Output enable type:   LowActive
8
-- Source mapping:
9
--      test6Byte.bin bytes [0x0, 0x5] -> ROM byte range [0x0, 0x7]
10
11
library ieee;
12
use ieee.std_logic_1164.all;
13
use ieee.numeric_std.all;
14
15
entity ROM is 
16
 port(
17
  OE_n : in std_logic; --! Output enable input (L-active)
18
  A : in std_logic_vector(9 downto 0); --! Address bus
19
  D : out std_logic_vector(31 downto 0)); --! Data bus
20
end ROM;
21
22
architecture BEHAVIOR of ROM is 
23
 type romtable_t is array(0 to 1023) of std_logic_vector(31 downto 0);
24
 signal Dint : std_logic_vector(31 downto 0);
25
 constant ROMdata : romtable_t := (
26
  0 => x"01020304",
27
  1 => x"05060000",
28
  others => x"ffffffff");
29
30
begin
31
 process (A)
32
 begin
33
    Dint <= ROMdata(to_integer(unsigned(A)));
34
 end process;
35
36
 D <= Dint when OE_n='0' else (others => 'Z');
37
end BEHAVIOR;

von Rüdiger (Gast)


Lesenswert?

Ich habe das Programm erfolgreich für ein Z80-Projekt einsetzen können. 
Per Makefile kann ich das ROM direkt nach dem Assembler-Lauf generieren 
lassen.
Funktionieren tut es, der Z80 zählt brav die Binärwerte hoch.

Allerdings zeigt mit Quartus in der Zusammenfassung "Total memory bits: 
0".
Bedeuted dies, daß kein Block-RAM zur Implementierung verwendet wurde?
Wie müßte (wenn überhaupt sinnvoll) der Quelltext abgeändert werden?
1
-- Creation time:  Sun Jul 12 20:15:04 2015
2
-- Address bits:   10
3
-- Data bus bits:   8
4
-- Endianess:  BigEndian
5
-- Active clock flank:   None
6
-- Output enable type:   LowActive
7
-- Source mapping:
8
--   program.bin bytes [0x0, 0x13] -> ROM byte range [0x0, 0x13]
9
10
library ieee;
11
use ieee.std_logic_1164.all;
12
use ieee.numeric_std.all;
13
14
entity ROM is 
15
 port(
16
  OE_n : in std_logic; --! Output enable input (L-active)
17
  A : in std_logic_vector(9 downto 0); --! Address bus
18
  D : out std_logic_vector(7 downto 0)); --! Data bus
19
end ROM;
20
21
architecture BEHAVIOR of ROM is 
22
 type romtable_t is array(0 to 1023) of std_logic_vector(7 downto 0);
23
 signal Dint : std_logic_vector(7 downto 0);
24
 constant ROMdata : romtable_t := (
25
  0 => x"3e", -- program.bin bytes [0x0, 0x13] -> ROM byte range [0x0, 0x13]
26
  1 => x"00",
27
  2 => x"d3",
28
  3 => x"00",
29
  4 => x"06",
30
  5 => x"ff",
31
  6 => x"16",
32
  7 => x"ff",
33
  8 => x"15",
34
  9 => x"c2",
35
  10 => x"08",
36
  11 => x"00",
37
  12 => x"05",
38
  13 => x"c2",
39
  14 => x"06",
40
  15 => x"00",
41
  16 => x"3c",
42
  17 => x"c3",
43
  18 => x"02",
44
  19 => x"00",
45
  others => x"ff");
46
47
begin
48
 process (A)
49
 begin
50
    Dint <= ROMdata(to_integer(unsigned(A)));
51
 end process;
52
53
 D <= Dint when OE_n='0' else (others => 'Z');
54
end BEHAVIOR;

von Lattice User (Gast)


Lesenswert?

Rüdiger schrieb:
>
> Allerdings zeigt mit Quartus in der Zusammenfassung "Total memory bits:
> 0".
> Bedeuted dies, daß kein Block-RAM zur Implementierung verwendet wurde?
> Wie müßte (wenn überhaupt sinnvoll) der Quelltext abgeändert werden?
>

Damit er Blockram verwendet, braucht es mit hoher Wahrscheinlichkeit 
eine Clock. Näheres findet man in den Coding Rules des Synthese Tools.

Noch etwas: innerhalb eines FPGAs gibt es kein 'Z', das OE macht also 
nicht das was du dir vorstellst.

von Rüdiger (Gast)


Lesenswert?

Richtig, wenn ich das ROM getaktet erzeuge, dann wird das Block-RAM 
verwendet (Option: --activeClockFlank=FallingEdge).

Das mit dem "Z"-Zustand verstehe ich allerdings nicht; dieser müßte doch 
durch Ausgangstreiber bereit gestellt werden?
Ansonsten macht std_logic ja auch kaum Sinn, denn die Motivation lag ja 
gerade im Zugriff auf gemeinsam genutzte Leitungen wie es hier durch den 
Datenbus notwendig geworden ist!

Und soweit ich mich erinnern kann, hat auch die SPI-Implementierung von 
OpenCores einige Leitungen mit 'Z' betrieben.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.