Hilfsprogramm zur ROM-Erzeugung geschrieben

#4177045
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.
Angehängte Dateien:
Gast #4179034
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
#4179942
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....
Gast #4181704
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.
Gast #4182663
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,
Gast #4184432
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.
(Firma: www.dossmatik.de) #4186450
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.
Gast #4186535
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
Angehängte Dateien:
#4195881
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;
Gast #4196062
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;
Gast #4196102
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.
Gast #4196668
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren