mirror of
https://github.com/ParkerTenBroeck/hdl_sim.git
synced 2026-06-06 21:24:06 -04:00
first
This commit is contained in:
commit
a266096f32
10 changed files with 593 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/build
|
||||||
1
conn/.gitignore
vendored
Normal file
1
conn/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
7
conn/Cargo.lock
generated
Normal file
7
conn/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vhdl_ui"
|
||||||
|
version = "0.1.0"
|
||||||
7
conn/Cargo.toml
Normal file
7
conn/Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
[package]
|
||||||
|
name = "vhdl_ui"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib"]
|
||||||
60
conn/src/lib.rs
Normal file
60
conn/src/lib.rs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
use std::{
|
||||||
|
io::{BufRead, BufReader},
|
||||||
|
sync::atomic::{AtomicU32, Ordering},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SimState{
|
||||||
|
switch: AtomicU32,
|
||||||
|
button: AtomicU32,
|
||||||
|
led: AtomicU32,
|
||||||
|
hex: AtomicU32,
|
||||||
|
}
|
||||||
|
|
||||||
|
static STATE: SimState = SimState{
|
||||||
|
switch: AtomicU32::new(0),
|
||||||
|
button: AtomicU32::new(0),
|
||||||
|
led: AtomicU32::new(0),
|
||||||
|
hex: AtomicU32::new(0),
|
||||||
|
};
|
||||||
|
|
||||||
|
fn client() {
|
||||||
|
let reader = BufReader::new(std::io::stdin());
|
||||||
|
for line in reader.lines().map_while(Result::ok) {
|
||||||
|
let line = line.trim();
|
||||||
|
if let Some(v) = line.strip_prefix("sw=") {
|
||||||
|
if let Ok(n) = v.parse::<u32>() {
|
||||||
|
STATE.switch.store(n, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
} else if let Some(v) = line.strip_prefix("key=") {
|
||||||
|
if let Ok(n) = v.parse::<u32>() {
|
||||||
|
STATE.button.store(n, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_init() {
|
||||||
|
std::thread::Builder::new().name("client".into()).spawn(client).expect("Failed to spawn client thread");
|
||||||
|
eprintln!("[ffi] initialzied");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_get_sw() -> u32 {
|
||||||
|
STATE.switch.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_get_key() -> u32 {
|
||||||
|
STATE.button.load(Ordering::Relaxed)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn ffi_set_outputs(led: u32, hex: u32) {
|
||||||
|
if STATE.led.swap(led, Ordering::Relaxed) != led{
|
||||||
|
println!("LED={:#x?}", STATE.led.load(Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
if STATE.hex.swap(hex, Ordering::Relaxed) != hex{
|
||||||
|
println!("HEX={:#x?}", STATE.hex.load(Ordering::Relaxed))
|
||||||
|
}
|
||||||
|
}
|
||||||
34
default.nix
Normal file
34
default.nix
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
{ pkgs ? import <nixpkgs> {} }:
|
||||||
|
pkgs.mkShell rec {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
# Replace llvmPackages with llvmPackages_X, where X is the latest LLVM version (at the time of writing, 16)
|
||||||
|
llvmPackages.bintools
|
||||||
|
rustup
|
||||||
|
ghdl-llvm
|
||||||
|
];
|
||||||
|
RUSTC_VERSION = "nightly";
|
||||||
|
# https://github.com/rust-lang/rust-bindgen#environment-variables
|
||||||
|
LIBCLANG_PATH = pkgs.lib.makeLibraryPath [ pkgs.llvmPackages_latest.libclang.lib ];
|
||||||
|
shellHook = ''
|
||||||
|
export PATH=$PATH:''${CARGO_HOME:-~/.cargo}/bin
|
||||||
|
export PATH=$PATH:''${RUSTUP_HOME:-~/.rustup}/toolchains/$RUSTC_VERSION-x86_64-unknown-linux-gnu/bin/
|
||||||
|
'';
|
||||||
|
# Add precompiled library to rustc search path
|
||||||
|
RUSTFLAGS = (builtins.map (a: ''-L ${a}/lib'') [
|
||||||
|
# add libraries here (e.g. pkgs.libvmi)
|
||||||
|
]);
|
||||||
|
# Add glibc, clang, glib and other headers to bindgen search path
|
||||||
|
BINDGEN_EXTRA_CLANG_ARGS =
|
||||||
|
# Includes with normal include path
|
||||||
|
(builtins.map (a: ''-I"${a}/include"'') [
|
||||||
|
# add dev libraries here (e.g. pkgs.libvmi.dev)
|
||||||
|
pkgs.glibc.dev
|
||||||
|
])
|
||||||
|
# Includes with special directory paths
|
||||||
|
++ [
|
||||||
|
''-I"${pkgs.llvmPackages_latest.libclang.lib}/lib/clang/${pkgs.llvmPackages_latest.libclang.version}/include"''
|
||||||
|
''-I"${pkgs.glib.dev}/include/glib-2.0"''
|
||||||
|
''-I${pkgs.glib.out}/lib/glib-2.0/include/''
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
26
rtl/circuit._vhdl
Normal file
26
rtl/circuit._vhdl
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
-- Do not modify the following entity block
|
||||||
|
entity circuit is
|
||||||
|
port (
|
||||||
|
clk: in std_logic; -- 500 Hz, period 2 ms
|
||||||
|
key: in std_logic_vector(3 downto 0); -- active low
|
||||||
|
sw: in std_logic_vector(9 downto 0); -- active high
|
||||||
|
led: out std_logic_vector(9 downto 0) := (others => '0'); -- active high
|
||||||
|
hex0: out std_logic_vector(6 downto 0) := (others => '0'); -- active low
|
||||||
|
hex1: out std_logic_vector(6 downto 0) := (others => '0') -- active low
|
||||||
|
);
|
||||||
|
end circuit;
|
||||||
|
|
||||||
|
|
||||||
|
architecture description of circuit is
|
||||||
|
signal counter: unsigned(9 downto 0) := "0000000000";
|
||||||
|
begin
|
||||||
|
led <= std_logic_vector(counter(9 downto 0));
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
counter <= counter+1;
|
||||||
|
end process;
|
||||||
|
end description;
|
||||||
329
rtl/circuit.vhdl
Normal file
329
rtl/circuit.vhdl
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
-- Do not modify the following entity block
|
||||||
|
entity circuit is
|
||||||
|
port (
|
||||||
|
clk: in std_logic;
|
||||||
|
key: in std_logic_vector(31 downto 0); -- active low
|
||||||
|
sw: in std_logic_vector(31 downto 0); -- active high
|
||||||
|
led: out std_logic_vector(31 downto 0); -- active high
|
||||||
|
hex: out std_logic_vector(31 downto 0) -- active low
|
||||||
|
);
|
||||||
|
end circuit;
|
||||||
|
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity alu is
|
||||||
|
Port (
|
||||||
|
func: in unsigned(3 downto 0);
|
||||||
|
a: in unsigned(7 downto 0);
|
||||||
|
b: in unsigned(7 downto 0);
|
||||||
|
carry_in: in std_logic;
|
||||||
|
o: out unsigned(7 downto 0);
|
||||||
|
carry_out: out std_logic;
|
||||||
|
zero: out std_logic;
|
||||||
|
gt: out std_logic;
|
||||||
|
lt: out std_logic;
|
||||||
|
eq: out std_logic
|
||||||
|
);
|
||||||
|
end alu;
|
||||||
|
|
||||||
|
architecture Behavioral of alu is
|
||||||
|
signal tmp: unsigned(8 downto 0);
|
||||||
|
begin
|
||||||
|
with func select
|
||||||
|
tmp <= ("0"&a) + ("0"&b) when x"0",
|
||||||
|
("0"&a) + ("0"&b) + (x"00"&carry_in) when x"1",
|
||||||
|
("0"&a) - ("0"&b) when x"2",
|
||||||
|
("0"&a) - ("0"&b) - (x"00"&carry_in) when x"3",
|
||||||
|
("0"&a) and ("0"&b) when x"4",
|
||||||
|
("0"&a) or ("0"&b) when x"5",
|
||||||
|
("0"&a) xor ("0"&b) when x"6",
|
||||||
|
"0"&x"00" when others;
|
||||||
|
|
||||||
|
zero <= '1' when tmp = 0 else '0';
|
||||||
|
eq <= '1' when a = b else '0';
|
||||||
|
lt <= '1' when a < b else '0';
|
||||||
|
gt <= '1' when a > b else '0';
|
||||||
|
carry_out <= tmp(8);
|
||||||
|
o <= tmp(7 downto 0);
|
||||||
|
|
||||||
|
end Behavioral ; -- Behavioral
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity ram_8x256 is
|
||||||
|
Port (
|
||||||
|
clk : in std_logic;
|
||||||
|
we : in std_logic; -- write enable
|
||||||
|
addr : in unsigned(7 downto 0); -- 8-bit address
|
||||||
|
din : in unsigned(7 downto 0); -- data input
|
||||||
|
dout : out unsigned(7 downto 0) -- data output
|
||||||
|
);
|
||||||
|
end ram_8x256;
|
||||||
|
|
||||||
|
architecture Behavioral of ram_8x256 is
|
||||||
|
type ram_type is array (0 to 255) of unsigned(7 downto 0);
|
||||||
|
signal ram : ram_type := (others => x"AB");
|
||||||
|
begin
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) then
|
||||||
|
if we = '1' then
|
||||||
|
ram(to_integer(unsigned(addr))) <= din;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
dout <= ram(to_integer(unsigned(addr)));
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
end Behavioral;
|
||||||
|
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity inst_ram_8x256 is
|
||||||
|
Port (
|
||||||
|
clk : in std_logic;
|
||||||
|
addr : in unsigned(7 downto 0); -- 8-bit address
|
||||||
|
dout : out unsigned(7 downto 0) -- data output
|
||||||
|
);
|
||||||
|
end inst_ram_8x256;
|
||||||
|
|
||||||
|
architecture Behavioral of inst_ram_8x256 is
|
||||||
|
type ram_type is array (0 to 255) of unsigned(7 downto 0);
|
||||||
|
signal ram : ram_type := (
|
||||||
|
0 => x"A0", -- 0 => a
|
||||||
|
2 => x"B1", -- 1 => b
|
||||||
|
3 => x"10", -- a+b => out
|
||||||
|
4 => x"AE", -- out => a
|
||||||
|
5 => x"10", -- a+b => out
|
||||||
|
6 => x"BE", -- out => b
|
||||||
|
7 => x"D0", -- jump to 3
|
||||||
|
8 => x"03",
|
||||||
|
others => (others => '0')
|
||||||
|
);
|
||||||
|
begin
|
||||||
|
process(clk)
|
||||||
|
begin
|
||||||
|
if rising_edge(clk) or falling_edge(clk) then
|
||||||
|
dout <= ram(to_integer(unsigned(addr)));
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
end Behavioral;
|
||||||
|
|
||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
|
||||||
|
architecture description of circuit is
|
||||||
|
signal clock: std_logic;
|
||||||
|
|
||||||
|
signal reg_pc: unsigned(7 downto 0) := "00000000";
|
||||||
|
signal reg_a: unsigned(7 downto 0) := "00000000";
|
||||||
|
signal reg_b: unsigned(7 downto 0) := "00000000";
|
||||||
|
signal reg_out: unsigned(7 downto 0) := "00000000";
|
||||||
|
|
||||||
|
signal inst_reg: unsigned(7 downto 0);
|
||||||
|
signal inst_bus: unsigned(7 downto 0);
|
||||||
|
|
||||||
|
signal data_read: unsigned(7 downto 0);
|
||||||
|
signal data_write: unsigned(7 downto 0);
|
||||||
|
|
||||||
|
signal data_addr: unsigned(7 downto 0) := "00000000";
|
||||||
|
signal data_write_e: std_logic := '0';
|
||||||
|
|
||||||
|
signal flag_carry: std_logic := '0';
|
||||||
|
signal flag_lt: std_logic := '0';
|
||||||
|
signal flag_gt: std_logic := '0';
|
||||||
|
signal flag_eq: std_logic := '0';
|
||||||
|
signal flag_zero: std_logic := '0';
|
||||||
|
|
||||||
|
signal alu_a, alu_b, alu_o : unsigned(7 downto 0);
|
||||||
|
signal alu_func : unsigned(3 downto 0);
|
||||||
|
signal alu_carry, alu_zero, alu_gt, alu_lt, alu_eq : std_logic;
|
||||||
|
|
||||||
|
function dec7seg(val: unsigned(3 downto 0)) return std_logic_vector is
|
||||||
|
begin
|
||||||
|
case val is
|
||||||
|
when "0000"=> return "1000000"; --0
|
||||||
|
when "0001"=> return "1111001"; --1
|
||||||
|
when "0010"=> return "0100100"; --2
|
||||||
|
when "0011"=> return "0110000"; --3
|
||||||
|
when "0100"=> return "0011001"; --4
|
||||||
|
when "0101"=> return "0010010"; --5
|
||||||
|
when "0110"=> return "0000010"; --6
|
||||||
|
when "0111"=> return "1111000"; --7
|
||||||
|
when "1000"=> return "0000000"; --8
|
||||||
|
when "1001"=> return "0011000"; --9
|
||||||
|
when "1010"=> return "0001000"; --A
|
||||||
|
when "1011"=> return "0000011"; --B
|
||||||
|
when "1100"=> return "1000110"; --C
|
||||||
|
when "1101"=> return "0100001"; --D
|
||||||
|
when "1110"=> return "0000110"; --E
|
||||||
|
when "1111"=> return "0001110"; --F
|
||||||
|
when others=> return "1111111"; ---
|
||||||
|
end case;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
-- hex(7 downto 4) <= dec7seg(reg_out(7 downto 4));
|
||||||
|
-- hex(3 downto 0) <= dec7seg(reg_out(3 downto 0));
|
||||||
|
|
||||||
|
clock <= clk when sw(9) = '1' else sw(8);
|
||||||
|
|
||||||
|
ram_inst : entity work.inst_ram_8x256
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
addr => reg_pc,
|
||||||
|
dout => inst_bus
|
||||||
|
);
|
||||||
|
|
||||||
|
ram_data : entity work.ram_8x256
|
||||||
|
port map(
|
||||||
|
clk => clk,
|
||||||
|
we => data_write_e,
|
||||||
|
addr => data_addr,
|
||||||
|
din => data_write,
|
||||||
|
dout => data_read
|
||||||
|
);
|
||||||
|
|
||||||
|
alu : entity work.alu
|
||||||
|
port map(
|
||||||
|
func => alu_func,
|
||||||
|
a => alu_a,
|
||||||
|
b => alu_b,
|
||||||
|
carry_in => flag_carry,
|
||||||
|
o => alu_o,
|
||||||
|
carry_out => alu_carry,
|
||||||
|
zero => alu_zero,
|
||||||
|
gt => alu_gt,
|
||||||
|
lt => alu_lt,
|
||||||
|
eq => alu_eq
|
||||||
|
);
|
||||||
|
|
||||||
|
process(clock)
|
||||||
|
variable out_extended : unsigned(8 downto 0);
|
||||||
|
begin
|
||||||
|
|
||||||
|
if rising_edge(clock) then
|
||||||
|
inst_reg <= inst_bus;
|
||||||
|
data_write_e <= '0';
|
||||||
|
|
||||||
|
report "begin reg_a = " & integer'image(to_integer(unsigned(reg_a)))
|
||||||
|
& " reg_b = " & integer'image(to_integer(unsigned(reg_b)))
|
||||||
|
& " reg_out = " & integer'image(to_integer(unsigned(reg_out)))
|
||||||
|
& " reg_pc = " & integer'image(to_integer(unsigned(reg_pc)))
|
||||||
|
& " inst_bus = " & integer'image(to_integer(unsigned(inst_bus)));
|
||||||
|
|
||||||
|
-- alu operations a,b
|
||||||
|
if inst_reg(7 downto 4) = x"1" then
|
||||||
|
alu_func <= inst_reg(3 downto 0);
|
||||||
|
alu_a <= reg_a;
|
||||||
|
alu_b <= reg_b;
|
||||||
|
reg_out <= alu_o;
|
||||||
|
end if;
|
||||||
|
-- alu operations a,imm
|
||||||
|
if inst_reg(7 downto 4) = x"2" then
|
||||||
|
alu_func <= inst_reg(3 downto 0);
|
||||||
|
alu_a <= reg_a;
|
||||||
|
reg_pc <= reg_pc+1;
|
||||||
|
end if;
|
||||||
|
-- alu operations imm,b
|
||||||
|
if inst_reg(7 downto 4) = x"3" then
|
||||||
|
alu_func <= inst_reg(3 downto 0);
|
||||||
|
alu_b <= reg_b;
|
||||||
|
reg_pc <= reg_pc+1;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
case inst_bus is
|
||||||
|
-- nop
|
||||||
|
when x"00" => null;
|
||||||
|
|
||||||
|
|
||||||
|
-- 0 => a
|
||||||
|
when x"A0" => reg_a <= x"00";
|
||||||
|
-- 1 => a
|
||||||
|
when x"A1" => reg_a <= x"01";
|
||||||
|
-- mem[reg b] => a
|
||||||
|
when x"AC" =>
|
||||||
|
data_addr <= reg_b;
|
||||||
|
-- out => a
|
||||||
|
when x"AE" => reg_a <= reg_out;
|
||||||
|
-- immediate => a
|
||||||
|
when x"AF" => reg_pc <= reg_pc+1;
|
||||||
|
|
||||||
|
-- 0 => b
|
||||||
|
when x"B0" => reg_b <= x"00";
|
||||||
|
-- 1 => b
|
||||||
|
when x"B1" => reg_b <= x"01";
|
||||||
|
-- mem[reg a] => b
|
||||||
|
when x"BC" =>
|
||||||
|
data_addr <= reg_b;
|
||||||
|
-- out => b
|
||||||
|
when x"BE" => reg_b <= reg_out;
|
||||||
|
-- immediate => b
|
||||||
|
when x"BF" => reg_pc <= reg_pc+1;
|
||||||
|
|
||||||
|
-- conditional
|
||||||
|
|
||||||
|
-- jump imm addr abs
|
||||||
|
when x"D0" => reg_pc <= reg_pc+1;
|
||||||
|
-- jump imm addr rel
|
||||||
|
when x"D1" => reg_pc <= reg_pc+1;
|
||||||
|
-- jump addr reg a
|
||||||
|
when x"DA" => reg_pc <= reg_a-1;
|
||||||
|
-- jump addr reg b
|
||||||
|
when x"DB" => reg_pc <= reg_b-1;
|
||||||
|
|
||||||
|
-- halt
|
||||||
|
when x"FF" => reg_pc <= reg_pc-1;
|
||||||
|
|
||||||
|
when others => null;
|
||||||
|
end case;
|
||||||
|
end if;
|
||||||
|
|
||||||
|
if falling_edge(clock) then
|
||||||
|
case inst_reg is
|
||||||
|
when x"AC" => reg_a <= data_read;
|
||||||
|
when x"AF" => reg_a <= inst_bus;
|
||||||
|
|
||||||
|
when x"BC" => reg_b <= data_read;
|
||||||
|
when x"BF" => reg_b <= inst_bus;
|
||||||
|
|
||||||
|
when others => null;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
|
||||||
|
case inst_reg is
|
||||||
|
-- jump imm addr abs
|
||||||
|
when x"D0" => reg_pc <= inst_bus;
|
||||||
|
-- jump imm addr rel
|
||||||
|
when x"D1" => reg_pc <= reg_pc+inst_bus;
|
||||||
|
|
||||||
|
when others => reg_pc <= reg_pc+1;
|
||||||
|
end case;
|
||||||
|
|
||||||
|
report "end reg_a = " & integer'image(to_integer(unsigned(reg_a)))
|
||||||
|
& " reg_b = " & integer'image(to_integer(unsigned(reg_b)))
|
||||||
|
& " reg_out = " & integer'image(to_integer(unsigned(reg_out)))
|
||||||
|
& " reg_pc = " & integer'image(to_integer(unsigned(reg_pc)))
|
||||||
|
& " inst_bus = " & integer'image(to_integer(unsigned(inst_bus)));
|
||||||
|
|
||||||
|
|
||||||
|
end if;
|
||||||
|
|
||||||
|
end process;
|
||||||
|
end description;
|
||||||
94
rtl/tb.vhdl
Normal file
94
rtl/tb.vhdl
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity tb is
|
||||||
|
end entity;
|
||||||
|
|
||||||
|
architecture sim of tb is
|
||||||
|
signal clk : std_logic := '0';
|
||||||
|
signal key : std_logic_vector(31 downto 0) := (others => '1'); -- active low
|
||||||
|
signal sw : std_logic_vector(31 downto 0) := (others => '0');
|
||||||
|
|
||||||
|
signal led : std_logic_vector(31 downto 0) := (others => '0');
|
||||||
|
signal hex : std_logic_vector(31 downto 0) := (others => '0');
|
||||||
|
|
||||||
|
|
||||||
|
-- Foreign subprograms MUST be declared in the declarative region (here),
|
||||||
|
-- and MUST have a body (even dummy) to satisfy VHDL.
|
||||||
|
procedure ffi_init is
|
||||||
|
begin
|
||||||
|
end procedure;
|
||||||
|
attribute foreign of ffi_init : procedure is
|
||||||
|
"VHPIDIRECT ffi_init";
|
||||||
|
|
||||||
|
function ffi_get_sw return integer is
|
||||||
|
begin
|
||||||
|
return 0;
|
||||||
|
end function;
|
||||||
|
attribute foreign of ffi_get_sw : function is
|
||||||
|
"VHPIDIRECT ffi_get_sw";
|
||||||
|
|
||||||
|
function ffi_get_key return integer is
|
||||||
|
begin
|
||||||
|
return 0;
|
||||||
|
end function;
|
||||||
|
attribute foreign of ffi_get_key : function is "VHPIDIRECT ffi_get_key";
|
||||||
|
|
||||||
|
procedure ffi_set_outputs(led_i : integer; hex_i : integer) is
|
||||||
|
begin
|
||||||
|
end procedure;
|
||||||
|
attribute foreign of ffi_set_outputs : procedure is
|
||||||
|
"VHPIDIRECT ffi_set_outputs";
|
||||||
|
|
||||||
|
function clean_slv(v : std_logic_vector) return std_logic_vector is
|
||||||
|
variable r : std_logic_vector(v'range);
|
||||||
|
begin
|
||||||
|
for i in v'range loop
|
||||||
|
if v(i) = '1' then
|
||||||
|
r(i) := '1';
|
||||||
|
else
|
||||||
|
r(i) := '0';
|
||||||
|
end if;
|
||||||
|
end loop;
|
||||||
|
return r;
|
||||||
|
end function;
|
||||||
|
|
||||||
|
begin
|
||||||
|
dut: entity work.circuit
|
||||||
|
port map (
|
||||||
|
clk => clk,
|
||||||
|
key => key,
|
||||||
|
sw => sw,
|
||||||
|
led => led,
|
||||||
|
hex => hex
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 500 Hz clock (2 ms period)
|
||||||
|
clk <= not clk after 1 ms;
|
||||||
|
|
||||||
|
process
|
||||||
|
variable sw_i : integer;
|
||||||
|
variable key_i : integer;
|
||||||
|
begin
|
||||||
|
ffi_init; -- starts Rust listener thread
|
||||||
|
wait for 0 ns;
|
||||||
|
|
||||||
|
|
||||||
|
while true loop
|
||||||
|
wait until rising_edge(clk) or falling_edge(clk);
|
||||||
|
|
||||||
|
sw_i := ffi_get_sw;
|
||||||
|
key_i := ffi_get_key;
|
||||||
|
|
||||||
|
sw <= std_logic_vector(to_unsigned(sw_i, 32));
|
||||||
|
key <= std_logic_vector(to_unsigned(key_i, 32));
|
||||||
|
|
||||||
|
ffi_set_outputs(
|
||||||
|
to_integer(unsigned(clean_slv(led))),
|
||||||
|
to_integer(unsigned(clean_slv(hex)))
|
||||||
|
);
|
||||||
|
end loop;
|
||||||
|
end process;
|
||||||
|
|
||||||
|
end architecture;
|
||||||
34
run.sh
Executable file
34
run.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
mkdir -p build
|
||||||
|
|
||||||
|
# Build Rust shared library
|
||||||
|
pushd conn >/dev/null
|
||||||
|
cargo build --release
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
pushd build >/dev/null
|
||||||
|
|
||||||
|
LIBSRC="../conn/target/release/libvhdl_ui.a"
|
||||||
|
LIBDIR="../conn/target/release"
|
||||||
|
|
||||||
|
|
||||||
|
ghdl -a --std=08 ../rtl/*.vhdl
|
||||||
|
|
||||||
|
ghdl -e --std=08 \
|
||||||
|
-Wl,"$LIBSRC" \
|
||||||
|
-Wl,-Wl,-rpath -Wl,-Wl,$LIBDIR \
|
||||||
|
tb
|
||||||
|
|
||||||
|
|
||||||
|
echo "=== Running sim ==="
|
||||||
|
echo "Connect and stream inputs using:"
|
||||||
|
echo " nc 127.0.0.1 5555"
|
||||||
|
echo "Then type lines like:"
|
||||||
|
echo " sw=1"
|
||||||
|
echo " key=15"
|
||||||
|
echo " key=7 (press KEY3 if bit3 becomes 0, etc; active-low)"
|
||||||
|
echo
|
||||||
|
|
||||||
|
ghdl -r --std=08 tb
|
||||||
Loading…
Add table
Add a link
Reference in a new issue