1
0
mirror of https://github.com/wfjm/w11.git synced 2026-04-25 20:01:57 +00:00
Files
wfjm.w11/rtl/bplib/sysmon/sysmon_rbus_core.vhd
2019-07-12 19:01:49 +02:00

366 lines
13 KiB
VHDL

-- $Id: sysmon_rbus_core.vhd 1181 2019-07-08 17:00:50Z mueller $
-- SPDX-License-Identifier: GPL-3.0-or-later
-- Copyright 2016-2019 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
--
------------------------------------------------------------------------------
-- Module Name: sysmon_rbus_core - syn
-- Description: SYSMON interface to rbus (generic)
--
-- Dependencies: -
--
-- Test bench: -
--
-- Target Devices: generic (all with SYSMON or XADC)
-- Tool versions: viv 2015.4-2019.1; ghdl 0.33-0.35
--
-- Revision History:
-- Date Rev Version Comment
-- 2016-05-25 767 1.0.1 don't init N_REGS (vivado fix for fsm inference)
-- BUGFIX: use s_init in regs_init (was s_idle)
-- 2016-03-12 741 1.0 Initial version
-- 2016-03-06 738 0.1 First draft
------------------------------------------------------------------------------
--
-- rbus registers:
-- - in general 1-to-1 mapping to sysmon/xadc address space
-- --> see function in sysmon/xadc user guide
-- - 8 addresses are implemented on the controller (base is ibase, default x"78")
-- --> see function below
--
-- Addr Bits Name r/w/f Function
-- 000 cntl -/-/f cntl
-- 15 reset -/-/f reset SYSMON
-- 001 stat r/w/- stat
-- 3 jlock r/c/- JTAGLOCKED seen
-- 2 jmod r/c/- JTAGMODIFIED seen
-- 1 jbusy r/c/- JTAGBUSY seen
-- 0 ot r/c/- OT seen
-- 010 almh r/w/- alm history
-- *:00 alm r/c/- ALM(*:0) seen
-- 011 -/-/- <unused>
-- 100 temp r/-/- current temp value
-- 101 alm r/-/- current alm value
-- *:00 alm r/-/- alm(*:0)
-- 110 -/-/- <unused>
-- 111 eos r/-/- eos counter
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.slvtypes.all;
use work.rblib.all;
use work.sysmonrbuslib.all;
-- ----------------------------------------------------------------------------
entity sysmon_rbus_core is -- SYSMON interface to rbus
generic (
DAWIDTH : positive := 7; -- drp address bus width
ALWIDTH : positive := 8; -- alm width
TEWIDTH : positive := 12; -- temp width
IBASE : slv8 := x"78"; -- base of controller register window
RB_ADDR : slv16 := x"fb00");
port (
CLK : in slbit; -- clock
RESET : in slbit := '0'; -- reset
RB_MREQ : in rb_mreq_type; -- rbus: request
RB_SRES : out rb_sres_type; -- rbus: response
SM_DEN : out slbit; -- sysmon: drp enable
SM_DWE : out slbit; -- sysmon: drp write enable
SM_DADDR : out slv(DAWIDTH-1 downto 0); -- sysmon: drp address
SM_DI : out slv16; -- sysmon: data input
SM_DO : in slv16; -- sysmon: data output
SM_DRDY : in slbit; -- sysmon: data ready
SM_EOS : in slbit; -- sysmon: end of scan
SM_RESET : out slbit; -- sysmon: reset
SM_ALM : in slv(ALWIDTH-1 downto 0);-- sysmon: alarms
SM_OT : in slbit; -- sysmon: overtemperature
SM_JTAGBUSY : in slbit; -- sysmon: JTAGBUSY
SM_JTAGLOCKED : in slbit; -- sysmon: JTAGLOCKED
SM_JTAGMODIFIED : in slbit; -- sysmon: JTAGMODIFIED
TEMP : out slv(TEWIDTH-1 downto 0) -- die temp
);
end sysmon_rbus_core;
architecture syn of sysmon_rbus_core is
type state_type is (
s_init, -- init: wait for jtaglocked down
s_idle, -- idle: dispatch
s_wait, -- wait: wait on drdy
s_twait -- twait: wait on drdy of temp read
);
type regs_type is record
rbsel : slbit; -- rbus select
state : state_type; -- state
eoscnt : slv16; -- eos counter
stat_ot : slbit; -- stat: ot
stat_jlock : slbit; -- stat: jtag locked
stat_jmod : slbit; -- stat: jtag modified
stat_jbusy : slbit; -- stat: jtag busy
almh : slv(ALWIDTH-1 downto 0); -- almh
temp : slv(TEWIDTH-1 downto 0); -- temp value
tpend : slbit; -- temp pending
end record regs_type;
constant regs_init : regs_type := (
'0', -- rbsel
s_init, -- state
(others=>'0'), -- eoscnt
'0','0','0','0', -- stat_ot, stat_j*
slv(to_unsigned(0,ALWIDTH)), -- almh
slv(to_unsigned(0,TEWIDTH)), -- temp
'0' -- tpend
);
signal R_REGS : regs_type := regs_init; -- state registers
signal N_REGS : regs_type; -- don't init (vivado fix for fsm infer)
-- only internal regs have names, only 3 LSB in constant
constant rbaddr_cntl: slv3 := "000"; -- 0 -/-/f
constant rbaddr_stat: slv3 := "001"; -- 1 r/w/-
constant rbaddr_almh: slv3 := "010"; -- 2 r/w/-
constant rbaddr_temp: slv3 := "100"; -- 4 r/-/-
constant rbaddr_alm: slv3 := "101"; -- 5 r/-/-
constant rbaddr_eos: slv3 := "111"; -- 7 r/-/-
constant cntl_rbf_reset: integer := 15;
constant stat_rbf_jlock: integer := 3;
constant stat_rbf_jmod: integer := 2;
constant stat_rbf_jbusy: integer := 1;
constant stat_rbf_ot: integer := 0;
begin
assert DAWIDTH=7 or DAWIDTH=8
report "assert(DAWIDTH=7 or DAWIDTH=8): unsupported DAWIDTH"
severity failure;
assert ALWIDTH<=16
report "assert ALWIDTH<16: unsupported ALWIDTH"
severity failure;
assert TEWIDTH=10 or TEWIDTH=12
report "assert(TEWIDTH=10 or TEWIDTH=12): unsupported TEWIDTH"
severity failure;
assert IBASE(2 downto 0) = "000"
report "assert IBASE(2:0) = 000: invalid IBASE"
severity failure;
proc_regs: process (CLK)
begin
if rising_edge(CLK) then
if RESET = '1' then
R_REGS <= regs_init;
else
R_REGS <= N_REGS;
end if;
end if;
end process proc_regs;
proc_next: process (R_REGS, RB_MREQ, SM_DO, SM_DRDY, SM_EOS, SM_ALM, SM_OT,
SM_JTAGLOCKED, SM_JTAGMODIFIED, SM_JTAGBUSY)
variable r : regs_type := regs_init;
variable n : regs_type := regs_init;
variable irb_ack : slbit := '0';
variable irb_busy : slbit := '0';
variable irb_err : slbit := '0';
variable irb_dout : slv16 := (others=>'0');
variable irbena : slbit := '0';
variable irb_addr_ext : slbit := '0';
variable irb_addr_int : slbit := '0';
variable ism_den : slbit := '0';
variable ism_dwe : slbit := '0';
variable ism_daddr : slv(DAWIDTH-1 downto 0) := (others=>'0');
variable ism_reset : slbit := '0';
begin
r := R_REGS;
n := R_REGS;
irb_ack := '0';
irb_busy := '0';
irb_err := '0';
irb_dout := (others=>'0');
irbena := RB_MREQ.re or RB_MREQ.we;
-- check for internal rbus controller register window
irb_addr_int := '0';
if RB_MREQ.addr(DAWIDTH-1 downto 3) = IBASE(DAWIDTH-1 downto 3) then
irb_addr_int := '1';
end if;
ism_den := '0';
ism_dwe := '0';
ism_daddr := RB_MREQ.addr(DAWIDTH-1 downto 0); -- default
ism_reset := '0';
-- handle EOS
if SM_EOS = '1' then
n.tpend := '1'; -- queue temp read
n.eoscnt := slv(unsigned(r.eoscnt) + 1); -- and count it
end if;
-- update stat and almh register fields
n.stat_ot := r.stat_ot or SM_OT;
n.stat_jlock := r.stat_jlock or SM_JTAGLOCKED;
n.stat_jmod := r.stat_jmod or SM_JTAGMODIFIED;
n.stat_jbusy := r.stat_jbusy or SM_JTAGBUSY;
n.almh := r.almh or SM_ALM;
-- rbus address decoder
n.rbsel := '0';
if RB_MREQ.aval='1' and RB_MREQ.addr(15 downto 7)=RB_ADDR(15 downto 7) then
n.rbsel := '1';
end if;
irb_ack := r.rbsel and irbena; -- ack all accesses
irb_busy := irb_ack; -- busy is default
-- internal state machine
case r.state is
when s_init => -- init: wait for jtaglocked down ----
if SM_JTAGLOCKED = '0' then
n.stat_jlock := '0'; -- clear status
n.state := s_idle; -- start working
end if;
when s_idle => -- idle: dispatch --------------------
if r.tpend = '1' then -- temp update pending ?
n.tpend := '0'; -- mark done
if SM_JTAGLOCKED = '0' then -- if not jlocked
ism_daddr := "0000000"; -- temp is reg 00h
ism_dwe := '0'; -- do read
ism_den := '1'; -- start drp cycle
n.state := s_twait;
end if;
elsif r.rbsel = '1' then -- rbus access ?
if irb_addr_int ='1' then -- internal controller regs
irb_busy := '0';
case RB_MREQ.addr(2 downto 0) is
when rbaddr_cntl =>
if RB_MREQ.we = '1' then
ism_reset := RB_MREQ.din(cntl_rbf_reset);
end if;
when rbaddr_stat =>
if RB_MREQ.we = '1' then
n.stat_jlock := r.stat_jlock and
not RB_MREQ.din(stat_rbf_jlock);
n.stat_jmod := r.stat_jmod and
not RB_MREQ.din(stat_rbf_jmod);
n.stat_jbusy := r.stat_jbusy and
not RB_MREQ.din(stat_rbf_jbusy);
n.stat_ot := r.stat_ot and
not RB_MREQ.din(stat_rbf_ot);
end if;
when rbaddr_almh =>
if RB_MREQ.we = '1' then
n.almh := r.almh and not RB_MREQ.din(r.almh'range);
end if;
when rbaddr_temp =>
irb_err := RB_MREQ.we;
when rbaddr_alm =>
irb_err := RB_MREQ.we;
when rbaddr_eos =>
irb_err := RB_MREQ.we;
when others =>
irb_err := irbena;
end case;
else -- sysmon reg access
if irbena = '1' then
if SM_JTAGLOCKED = '0' then -- if not jlocked
ism_daddr := RB_MREQ.addr(ism_daddr'range);
ism_dwe := RB_MREQ.we;
ism_den := '1'; -- start drp cycle
n.state := s_wait;
else
irb_err := '1'; -- quit with error if jlocked
end if;
end if;
end if;
end if;
when s_wait => -- wait: wait on drdy ----------------
n.state := s_wait;
if SM_DRDY = '1' then
irb_busy := '0';
n.state := s_idle;
end if;
when s_twait => -- twait: wait on drdy of temp read --
n.state := s_twait;
if SM_DRDY = '1' then
n.temp := SM_DO(15 downto 16-TEWIDTH); -- take msb's
n.state := s_idle;
end if;
when others => null; -- <> ------------------------------
end case; -- case r.state
-- rbus output driver
if r.rbsel = '1' then
if irb_addr_int = '1' then
case RB_MREQ.addr(2 downto 0) is
when rbaddr_stat =>
irb_dout(stat_rbf_jlock) := r.stat_jlock;
irb_dout(stat_rbf_jmod) := r.stat_jmod;
irb_dout(stat_rbf_jbusy) := r.stat_jbusy;
irb_dout(stat_rbf_ot) := r.stat_ot;
when rbaddr_almh =>
irb_dout(r.almh'range) := r.almh;
when rbaddr_temp =>
irb_dout(r.temp'range) := r.temp;
when rbaddr_alm =>
irb_dout(SM_ALM'range) := SM_ALM;
when rbaddr_eos =>
irb_dout := r.eoscnt;
when others =>
irb_dout := (others=>'0');
end case;
else
irb_dout := SM_DO;
end if;
end if;
N_REGS <= n;
SM_DEN <= ism_den;
SM_DWE <= ism_dwe;
SM_DADDR <= ism_daddr;
SM_DI <= RB_MREQ.din;
SM_RESET <= ism_reset;
TEMP <= r.temp;
RB_SRES <= rb_sres_init;
RB_SRES.ack <= irb_ack;
RB_SRES.busy <= irb_busy;
RB_SRES.err <= irb_err;
RB_SRES.dout <= irb_dout;
end process proc_next;
end syn;