From 900c57c5818fdcaceccdbb716a510f3b2412f95f Mon Sep 17 00:00:00 2001 From: Cole Poirier Date: Tue, 11 Aug 2020 14:48:53 -0700 Subject: [PATCH] mmu.py fix formatting, use Cat() where '&' in mmu.vhdl --- src/soc/experiment/mmu.py | 1014 +++++++++++++++++++++---------------- 1 file changed, 570 insertions(+), 444 deletions(-) diff --git a/src/soc/experiment/mmu.py b/src/soc/experiment/mmu.py index aeda3a58..96a60d45 100644 --- a/src/soc/experiment/mmu.py +++ b/src/soc/experiment/mmu.py @@ -9,12 +9,14 @@ from nmigen import (Module, Signal, Elaboratable, Mux, Cat, Repl, signed, from nmigen.cli import main from nmigen.iocontrol import RecordObject -# library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +# library ieee; use ieee.std_logic_1164.all; +# use ieee.numeric_std.all; # library work; use work.common.all; # -- Radix MMU -# -- Supports 4-level trees as in arch 3.0B, but not the two-step translation +# -- Supports 4-level trees as in arch 3.0B, but not the +# -- two-step translation # -- for guests under a hypervisor (i.e. there is no gRA -> hRA translation). # type state_t is @@ -109,8 +111,9 @@ class RegStage(RecordObject): # Radix MMU -# Supports 4-level trees as in arch 3.0B, but not the two-step translation -# for guests under a hypervisor (i.e. there is no gRA -> hRA translation). +# Supports 4-level trees as in arch 3.0B, but not the +# two-step translation for guests under a hypervisor +# (i.e. there is no gRA -> hRA translation). class MMU(Elaboratable): # entity mmu is # port ( @@ -133,83 +136,88 @@ class MMU(Elaboratable): self.d_in = DcacheToMmuType() self.i_out = MmuToIcacheType() - def elaborate(self, platform): -# -- Multiplex internal SPR values back to loadstore1, selected -# -- by l_in.sprn. +# signal addrsh : std_ulogic_vector(15 downto 0); +# signal mask : std_ulogic_vector(15 downto 0); +# signal finalmask : std_ulogic_vector(43 downto 0); + self.addrsh = Signal(16) + self.mask = Signal(16) + self.finalmask = Signal(44) - # Multiplex internal SPR values back to loadstore1, selected by - # l_in.sprn. +# signal r, rin : reg_stage_t; + self.r = RegStage() + self.rin = RegStage() + +# begin +def elaborate(self, platform): +# -- Multiplex internal SPR values back to loadstore1, +# -- selected by l_in.sprn. + # Multiplex internal SPR values back to loadstore1, + # selected by l_in.sprn. m = Module() comb = m.d.comb sync = m.d.sync rst = ResetSignal() - l_in = self.l_in + + l_in = self.l_in l_out = self.l_out d_out = self.d_out - d_in = self.d_in + d_in = self.d_in i_out = self.i_out - # non-existant variable, to be removed when I understand how to do VHDL - # rising_edge(clk) in nmigen - rising_edge = False - -# signal r, rin : reg_stage_t; - r = RegStage() - rin = RegStage() - -# signal addrsh : std_ulogic_vector(15 downto 0); -# signal mask : std_ulogic_vector(15 downto 0); -# signal finalmask : std_ulogic_vector(43 downto 0); - addrsh = Signal(16) - mask = Signal(16) - finalmask = Signal(44) + addrsh = self.addrsh + mask = self.mask + finalmask = self.finalmask -# begin + r = self.r + rin = self.rin # l_out.sprval <= r.prtbl when l_in.sprn(9) = '1' - with m.If(l_in.sprn[9] == 1): + with m.If(l_in.sprn[9]): comb += l_out.sprval.eq(r.prtbl) # else x"00000000" & r.pid; with m.Else(): - comb += l_out.sprval.eq(0x00000000 & r) + comb += l_out.sprval.eq(Cat(r.pid, + Const(0x00000000, 8)) # if rin.valid = '1' then -# report "MMU got tlb miss for " & to_hstring(rin.addr); +# report "MMU got tlb miss for " +# & to_hstring(rin.addr); # end if; - with m.If(rin.valid == 1): + with m.If(rin.valid): print(f"MMU got tlb miss for {rin.addr}") # if l_out.done = '1' then # report "MMU completing op without error"; # end if; - with m.If(l_out.done == 1): + with m.If(l_out.done): print("MMU completing op without error") # if l_out.err = '1' then # report "MMU completing op with err invalid=" & -# std_ulogic'image(l_out.invalid) & " badtree=" & -# std_ulogic'image(l_out.badtree); +# std_ulogic'image(l_out.invalid) & +# " badtree=" & std_ulogic'image( +# l_out.badtree); # end if; - with m.If(l_out.err == 1): - print(f"MMU completing op with err invalid={l_out.invalid} - badtree={l_out.badtree}") + with m.If(l_out.err): + print(f"MMU completing op with err invalid= + {l_out.invalid} badtree={l_out.badtree}") # if rin.state = RADIX_LOOKUP then -# report "radix lookup shift=" & integer'image(to_integer( -# rin.shift)) & " msize=" & integer'image(to_integer( -# rin.mask_size)); +# report "radix lookup shift=" & integer'image( +# to_integer(rin.shift)) & " msize=" & +# integer'image(to_integer(rin.mask_size)); # end if; with m.If(rin.state == State.RADIX_LOOKUP): print(f"radix lookup shift={rin.shift} msize={rin.mask_size}") # if r.state = RADIX_LOOKUP then -# report "send load addr=" & to_hstring(d_out.addr) & -# " addrsh=" & to_hstring(addrsh) & " mask=" & -# to_hstring(mask); +# report "send load addr=" & to_hstring(d_out.addr) +# & " addrsh=" & to_hstring(addrsh) & +# " mask=" & to_hstring(mask); # end if; with m.If(r.state == State.RADIX_LOOKUP): print(f"send load addr={d_out.addr} @@ -219,23 +227,21 @@ class MMU(Elaboratable): sync += r.eq(rin) # end process; -# -- Shift address bits 61--12 right by 0--47 bits and -# -- supply the least significant 16 bits of the result. -# addrshifter: process(all) - +# -- Shift address bits 61--12 right by 0--47 bits and +# -- supply the least significant 16 bits of the result. +# -- addrshifter: process(all) # Shift address bits 61--12 right by 0--47 bits and # supply the least significant 16 bits of the result. -class AddrShifter(Elaboratable): - +class AddrShifter(Elaboratable, MMU): def __init__(self): # variable sh1 : std_ulogic_vector(30 downto 0); # variable sh2 : std_ulogic_vector(18 downto 0); # variable result : std_ulogic_vector(15 downto 0); + super().__init__() self.sh1 = Signal(31) self.sh2 = Signal(19) self.result = Signal(16) - # begin def elaborate(self, platform): @@ -246,39 +252,43 @@ class AddrShifter(Elaboratable): rst = ResetSignal() - sh1 = self.sh1 - sh2 = self.sh2 + r = self.r + addrsh = self.addrsh + + sh1 = self.sh1 + sh2 = self.sh2 result = self.result # case r.shift(5 downto 4) is with m.Switch(r.shift[4:6]): # when "00" => # sh1 := r.addr(42 downto 12); - with m.Case(0): + with m.Case(Const(0b00, 2)): comb += sh1.eq(r.addr[12:43]) # when "01" => # sh1 := r.addr(58 downto 28); - with m.Case(1): + with m.Case(Const(0b01, 2)): comb += sh1.eq(r.addr[28:59]) # when others => # sh1 := "0000000000000" & r.addr(61 downto 44); with m.Default(): - comb += sh1.eq(r.addr[44:62]) + comb += sh1.eq(Cat(r.addr[44:62], + Const(0b0000000000000, 13)) # end case; # case r.shift(3 downto 2) is with m.Switch(r.shift[2:4]): # when "00" => # sh2 := sh1(18 downto 0); - with m.Case(0): + with m.Case(Const(0b00, 2)): comb += sh2.eq(sh1[0:19]) # when "01" => # sh2 := sh1(22 downto 4); - with m.Case(1): + with m.Case(Const(0b01, 2)): comb += sh2.eq(sh1[4:23]) # when "10" => # sh2 := sh1(26 downto 8); - with m.Case(2): + with m.Case(Const(0b10, 2)): comb += sh2.eq(sh1[8:27]) # when others => # sh2 := sh1(30 downto 12); @@ -290,15 +300,15 @@ class AddrShifter(Elaboratable): with m.Switch(r.shift[0:2]): # when "00" => # result := sh2(15 downto 0); - with m.Case(0): + with m.Case(Const(0b00, 2)): comb += result.eq(sh1[0:16]) # when "01" => # result := sh2(16 downto 1); - with m.Case(1): + with m.Case(Const(0b01, 2)): comb += result.eq(sh1[1:17]) # when "10" => # result := sh2(17 downto 2); - with m.Case(2): + with m.Case(Const(0b10, 2)): comb += result.eq(sh1[2:18]) # when others => # result := sh2(18 downto 3); @@ -306,16 +316,19 @@ class AddrShifter(Elaboratable): comb += result.eq(sh1[3:19]) # end case; # addrsh <= result; - comb += self.addrsh.eq(result) + comb += addrsh.eq(result) # end process; -# -- generate mask for extracting address fields for PTE address generation -# addrmaskgen: process(all) - # generate mask for extracting address fields for PTE address generation - class AddrMaskGen(Elaboratable): +# -- generate mask for extracting address fields for PTE address +# -- generation +# addrmaskgen: process(all) +# generate mask for extracting address fields for PTE address +# generation +class AddrMaskGen(Elaboratable, MMU): def __init__(self): # variable m : std_ulogic_vector(15 downto 0); - self.mask = Signal(16) + super().__init__() + self.msk = Signal(16) # begin def elaborate(self, platform): @@ -326,66 +339,73 @@ class AddrShifter(Elaboratable): rst = ResetSignal() + msk = self.msk + + r = self.r mask = self.mask # -- mask_count has to be >= 5 # m := x"001f"; # mask_count has to be >= 5 - comb += mask.eq(0x001F) + # TODO check hex conts with lkcl + comb += mask.eq(Const(0x001F, 5) # for i in 5 to 15 loop for i in range(5,16): # if i < to_integer(r.mask_size) then with m.If(i < r.mask_size): # m(i) := '1'; - comb += mask[i].eq(1) + comb += msk[i].eq(1) # end if; # end loop; # mask <= m; - comb += self.mask.eq(mask) + comb += mask.eq(msk) # end process; -# -# -- generate mask for extracting address bits to go in TLB entry -# -- in order to support pages > 4kB -# finalmaskgen: process(all) -# generate mask for extracting address bits to go in TLB entry -# in order to support pages > 4kB - class FinalMaskGen(Elaboratable): +# -- generate mask for extracting address bits to go in +# -- TLB entry in order to support pages > 4kB +# finalmaskgen: process(all) +# generate mask for extracting address bits to go in +# TLB entry in order to support pages > 4kB +class FinalMaskGen(Elaboratable, MMU): + def __init__(self): # variable m : std_ulogic_vector(43 downto 0); - def __init__(self): - self.mask = Signal(44) -# begin - def elaborate(self, platform): - m = Module() + super().__init__() + self.msk = Signal(44) - comb = m.d.comb - sync = m.d.sync +# begin + def elaborate(self, platform): + m = Module() - rst = ResetSignal() + comb = m.d.comb + sync = m.d.sync - mask = self.mask + rst = ResetSignal() + + mask = self.mask + r = self.r -# m := (others => '0'); - # TODO value should be vhdl (others => '0') in nmigen - comb += mask.eq(0) + msk = self.msk + +# m := (others => '0'); + # TODO value should be vhdl (others => '0') in nmigen + comb += msk.eq(0) # for i in 0 to 43 loop for i in range(44): # if i < to_integer(r.shift) then with m.If(i < r.shift): # m(i) := '1'; - comb += mask.eq(1) + comb += msk.eq(1) # end if; # end loop; # finalmask <= m; comb += self.finalmask(mask) # end process; -# -# mmu_1: process(all) - class MMU1(Elaboratable): - def __init__(self): +# mmu_1: process(all) +class MMU1(Elaboratable): + def __init__(self): # variable v : reg_stage_t; # variable dcreq : std_ulogic; # variable tlb_load : std_ulogic; @@ -500,400 +520,475 @@ class AddrShifter(Elaboratable): comb += prtbl_rd.eq(0) -# -- Radix tree data structures in memory are big-endian, -# -- so we need to byte-swap them +# -- Radix tree data structures in memory are +# -- big-endian, so we need to byte-swap them # for i in 0 to 7 loop - # Radix tree data structures in memory are big-endian, - # so we need to byte-swap them + # Radix tree data structures in memory are + # big-endian, so we need to byte-swap them for i in range(8): -# data(i * 8 + 7 downto i * 8) := d_in.data((7 - i) -# * 8 + 7 downto (7 - i) * 8); - comb += data[i * 8:i * 8 + 7 + 1].eq(d_in.data[ - (7 - i) * 8:(7 - i) * 8 + 7 + 1 - ]) +# data(i * 8 + 7 downto i * 8) := d_in.data( +# (7 - i) * 8 + 7 downto (7 - i) * 8); + comb += data[i * 8:i * 8 + 7 + 1].eq( + d_in.data[ + (7 - i) * 8:(7 - i) * 8 + 7 + 1 + ]) # end loop; # case r.state is with m.Switch(r.state): -# when IDLE => - with m.Case(State.IDLE): -# if l_in.addr(63) = '0' then -# pgtbl := r.pgtbl0; -# pt_valid := r.pt0_valid; - with m.If(l_in.addr[63] == 0): - comb += pgtbl.eq(r.pgtbl0) - comb += pt_valid.eq(r.pt0_valid) -# else -# pgtbl := r.pgtbl3; -# pt_valid := r.pt3_valid; - with m.Else(): - comb += pgtbl.eq(r.pt3_valid) - comb += pt_valid.eq(r.pt3_valid) -# end if; - -# -- rts == radix tree size, # address bits being translated -# rts := unsigned('0' & pgtbl(62 downto 61) & pgtbl(7 downto 5)); - # rts == radix tree size, number of address bits being translated - comb += rts.eq(((Cat(Const(0b0, 1), Cat(pgtbl[61:63], - pgtbl[5:8]))).as_unsigned()) - -# -- mbits == # address bits to index top level of tree -# mbits := unsigned('0' & pgtbl(4 downto 0)); - # mbits == number of address bits to index top level of tree - comb += mbits.eq((0 & pgtbl[0:5]).as_unsigned()) -# -- set v.shift to rts so that we can use finalmask for the -# segment check -# v.shift := rts; -# v.mask_size := mbits(4 downto 0); -# v.pgbase := pgtbl(55 downto 8) & x"00"; - # set v.shift to rts so that we can use finalmask for the segment - # check - comb += v.shift.eq(rts) - comb += v.mask_size.eq(mbits[0:5]) - comb += v.pgbase.eq(pgtbl[8:56] & 0x00) - -# if l_in.valid = '1' then - with m.If(l_in.valid == 1): -# v.addr := l_in.addr; -# v.iside := l_in.iside; -# v.store := not (l_in.load or l_in.iside); -# v.priv := l_in.priv; - comb += v.addr.eq(l_in.addr - comb += v.iside.eq(l_in.iside) - comb += v.store.eq(~(l_in.load | l_in.siside)) -# if l_in.tlbie = '1' then - with m.If(l_in.tlbie == 1): -# -- Invalidate all iTLB/dTLB entries for tlbie with -# -- RB[IS] != 0 or RB[AP] != 0, or for slbia -# v.inval_all := l_in.slbia or l_in.addr(11) or l_in. -# addr(10) or l_in.addr(7) or l_in.addr(6) -# or l_in.addr(5); - # Invalidate all iTLB/dTLB entries for tlbie with - # RB[IS] != 0 or RB[AP] != 0, or for slbia - comb += v.inval_all.eq(l_in.slbia | l_in.addr[11] | - l_in.addr[10] | l_in.addr[7] | - l_in.addr[6] | l_in.addr[5]) -# -- The RIC field of the tlbie instruction comes across -# -- on the sprn bus as bits 2--3. RIC=2 flushes process -# -- table caches. -# if l_in.sprn(3) = '1' then - # The RIC field of the tlbie instruction comes across - # on the sprn bus as bits 2--3. RIC=2 flushes process - # table caches. - with m.If(l_in.sprn[3] == 1): -# v.pt0_valid := '0'; -# v.pt3_valid := '0'; - comb += v.pt0_valid.eq(0) - comb += v.pt3_valid.eq(0) -# end if; -# v.state := DO_TLBIE; - comb += v.state.eq(State.DO_TLBIE) +# when IDLE => + with m.Case(State.IDLE): +# if l_in.addr(63) = '0' then +# pgtbl := r.pgtbl0; +# pt_valid := r.pt0_valid; + with m.If(~l_in.addr[63]): + comb += pgtbl.eq(r.pgtbl0) + comb += pt_valid.eq(r.pt0_valid) # else +# pgtbl := r.pgtbl3; +# pt_valid := r.pt3_valid; with m.Else(): -# v.valid := '1'; - comb += v.valid.eq(1) -# if pt_valid = '0' then - with m.If(pt_valid == 0): -# -- need to fetch process table entry -# -- set v.shift so we can use finalmask for generating -# -- the process table entry address -# v.shift := unsigned('0' & r.prtbl(4 downto 0)); -# v.state := PROC_TBL_READ; - # need to fetch process table entry - # set v.shift so we can use finalmask for generating - # the process table entry address - comb += v.shift.eq((0 & r.prtble[0:5]).as_unsigned()) - comb += v.state.eq(State.PROC_TBL_READ) - -# elsif mbits = 0 then - with m.If(mbits == 0): -# -- Use RPDS = 0 to disable radix tree walks -# v.state := RADIX_FINISH; -# v.invalid := '1'; - # Use RPDS = 0 to disable radix tree walks - comb += v.state.eq(State.RADIX_FINISH) - comb += v.invalid.eq(1) + comb += pgtbl.eq(r.pt3_valid) + comb += pt_valid.eq(r.pt3_valid) +# end if; + +# -- rts == radix tree size, # address bits being +# -- translated +# rts := unsigned('0' & pgtbl(62 downto 61) & +# pgtbl(7 downto 5)); + # rts == radix tree size, number of address bits + # being translated + comb += rts.eq((Cat( + Cat( + pgtbl[5:8], + pgtbl[61:63] + ), + Const(0b0,1) + )).as_unsigned()) + +# -- mbits == # address bits to index top level +# -- of tree +# mbits := unsigned('0' & pgtbl(4 downto 0)); + # mbits == number of address bits to index top + # level of tree + comb += mbits.eq(( + Cat(pgtbl[0:5], Const(0b0, 1)) + ).as_unsigned()) +# -- set v.shift to rts so that we can use finalmask +# -- for the segment check +# v.shift := rts; +# v.mask_size := mbits(4 downto 0); +# v.pgbase := pgtbl(55 downto 8) & x"00"; + # set v.shift to rts so that we can use finalmask + # for the segment check + comb += v.shift.eq(rts) + comb += v.mask_size.eq(mbits[0:5]) + comb += v.pgbase.eq(Cat( + Cont(0x00, 2), + pgtbl[8:56] + )) + +# if l_in.valid = '1' then + with m.If(l_in.valid): +# v.addr := l_in.addr; +# v.iside := l_in.iside; +# v.store := not (l_in.load or l_in.iside); +# v.priv := l_in.priv; + comb += v.addr.eq(l_in.addr + comb += v.iside.eq(l_in.iside) + comb += v.store.eq(~(l_in.load | l_in.siside)) +# if l_in.tlbie = '1' then + with m.If(l_in.tlbie): +# -- Invalidate all iTLB/dTLB entries for +# -- tlbie with RB[IS] != 0 or RB[AP] != 0, +# -- or for slbia +# v.inval_all := l_in.slbia or l_in.addr(11) +# or l_in.addr(10) or +# l_in.addr(7) or l_in.addr(6) +# or l_in.addr(5); + # Invalidate all iTLB/dTLB entries for + # tlbie with RB[IS] != 0 or RB[AP] != 0, + # or for slbia + comb += v.inval_all.eq(l_in.slbia + | l_in.addr[11] + | l_in.addr[10] + | l_in.addr[7] + | l_in.addr[6] + | l_in.addr[5] + ) +# -- The RIC field of the tlbie instruction +# -- comes across on the sprn bus as bits 2--3. +# -- RIC=2 flushes process table caches. +# if l_in.sprn(3) = '1' then + # The RIC field of the tlbie instruction + # comes across on the sprn bus as bits 2--3. + # RIC=2 flushes process table caches. + with m.If(l_in.sprn[3]): +# v.pt0_valid := '0'; +# v.pt3_valid := '0'; + comb += v.pt0_valid.eq(0) + comb += v.pt3_valid.eq(0) +# end if; +# v.state := DO_TLBIE; + comb += v.state.eq(State.DO_TLBIE) # else with m.Else(): -# v.state := SEGMENT_CHECK; - comb += v.state.eq(State.SEGMENT_CHECK) +# v.valid := '1'; + comb += v.valid.eq(1) +# if pt_valid = '0' then + with m.If(~pt_valid): +# -- need to fetch process table entry +# -- set v.shift so we can use finalmask +# -- for generating the process table +# -- entry address +# v.shift := unsigned('0' & r.prtbl( +# 4 downto 0)); +# v.state := PROC_TBL_READ; + # need to fetch process table entry + # set v.shift so we can use finalmask + # for generating the process table + # entry address + comb += v.shift.eq((Cat( + r.prtble[0:5], + Const(0b0, 1) + )).as_unsigned()) + comb += v.state.eq(State.PROC_TBL_READ) + +# elsif mbits = 0 then + with m.If(~mbits): +# -- Use RPDS = 0 to disable radix +# -- tree walks +# v.state := RADIX_FINISH; +# v.invalid := '1'; + # Use RPDS = 0 to disable radix + # tree walks + comb += v.state.eq(State.RADIX_FINISH) + comb += v.invalid.eq(1) +# else + with m.Else(): +# v.state := SEGMENT_CHECK; + comb += v.state.eq(State.SEGMENT_CHECK) +# end if; # end if; # end if; -# end if; -# if l_in.mtspr = '1' then - with m.If(l_in.mtspr == 1): -# -- Move to PID needs to invalidate L1 TLBs and cached -# -- pgtbl0 value. Move to PRTBL does that plus -# -- invalidating the cached pgtbl3 value as well. -# if l_in.sprn(9) = '0' then - # Move to PID needs to invalidate L1 TLBs and cached - # pgtbl0 value. Move to PRTBL does that plus - # invalidating the cached pgtbl3 value as well. - with m.If(l_in.sprn[9] == 0): -# v.pid := l_in.rs(31 downto 0); - comb += v.pid.eq(l_in.rs[0:32]) -# else - with m.Else(): -# v.prtbl := l_in.rs; -# v.pt3_valid := '0'; - comb += v.prtbl.eq(l_in.rs) - comb += v.pt3_valid.eq(0) -# end if; +# if l_in.mtspr = '1' then + with m.If(l_in.mtspr): +# -- Move to PID needs to invalidate L1 TLBs +# -- and cached pgtbl0 value. Move to PRTBL +# -- does that plus invalidating the cached +# -- pgtbl3 value as well. +# if l_in.sprn(9) = '0' then + # Move to PID needs to invalidate L1 TLBs + # and cached pgtbl0 value. Move to PRTBL + # does that plus invalidating the cached + # pgtbl3 value as well. + with m.If(~l_in.sprn[9]): +# v.pid := l_in.rs(31 downto 0); + comb += v.pid.eq(l_in.rs[0:32]) +# else + with m.Else(): +# v.prtbl := l_in.rs; +# v.pt3_valid := '0'; + comb += v.prtbl.eq(l_in.rs) + comb += v.pt3_valid.eq(0) +# end if; -# v.pt0_valid := '0'; -# v.inval_all := '1'; -# v.state := DO_TLBIE; - comb += v.pt0_valid.eq(0) - comb += v.inval_all.eq(0) - comb += v.state.eq(State.DO_TLBIE) -# end if; +# v.pt0_valid := '0'; +# v.inval_all := '1'; +# v.state := DO_TLBIE; + comb += v.pt0_valid.eq(0) + comb += v.inval_all.eq(0) + comb += v.state.eq(State.DO_TLBIE) +# end if; # when DO_TLBIE => - with m.Case(State.DO_TLBIE): -# dcreq := '1'; -# tlbie_req := '1'; -# v.state := TLB_WAIT; - comb += dcreq.eq(1) - comb += tlbie_req.eq(1) - comb += v.state.eq(State.TLB_WAIT) + with m.Case(State.DO_TLBIE): +# dcreq := '1'; +# tlbie_req := '1'; +# v.state := TLB_WAIT; + comb += dcreq.eq(1) + comb += tlbie_req.eq(1) + comb += v.state.eq(State.TLB_WAIT) # when TLB_WAIT => - with m.Case(State.TLB_WAIT): -# if d_in.done = '1' then - with m.If(d_in.done == 1): -# v.state := RADIX_FINISH; - comb += v.state.eq(State.RADIX_FINISH) -# end if; + with m.Case(State.TLB_WAIT): +# if d_in.done = '1' then + with m.If(d_in.done): +# v.state := RADIX_FINISH; + comb += v.state.eq(State.RADIX_FINISH) +# end if; # when PROC_TBL_READ => - with m.Case(State.PROC_TBL_READ): + with m.Case(State.PROC_TBL_READ): # dcreq := '1'; # prtbl_rd := '1'; # v.state := PROC_TBL_WAIT; - comb += dcreq.eq(1) - comb += prtbl_rd.eq(1) - comb += v.state.eq(State.PROC_TBL_WAIT) + comb += dcreq.eq(1) + comb += prtbl_rd.eq(1) + comb += v.state.eq(State.PROC_TBL_WAIT) # when PROC_TBL_WAIT => - with m.Case(State.PROC_TBL_WAIT): + with m.Case(State.PROC_TBL_WAIT): # if d_in.done = '1' then - with m.If(d_in.done == 1): + with m.If(d_in.done): # if r.addr(63) = '1' then - with m.If(r.addr[63] == 1): + with m.If(r.addr[63]): # v.pgtbl3 := data; # v.pt3_valid := '1'; - comb += v.pgtbl3.eq(data) - comb += v.pt3_valid.eq(1) -# else - with m.Else(): -# v.pgtbl0 := data; -# v.pt0_valid := '1'; - comb += v.pgtbl0.eq(data) - comb += v.pt0_valid.eq(1) -# end if; -# -- rts == radix tree size, # address bits being translated -# rts := unsigned('0' & data(62 downto 61) & data(7 downto 5)); - # rts == radix tree size, # address bits being translated - comb += rts.eq((0 & data[61:63] & data[5:8]).as_unsigned()) -# -- mbits == # address bits to index top level of tree -# mbits := unsigned('0' & data(4 downto 0)); - # mbits == # address bits to index top level of tree - comb += mbits.eq((0 & data[0:5]).as_unsigned()) -# -- set v.shift to rts so that we can use finalmask for the -# -- segment check + comb += v.pgtbl3.eq(data) + comb += v.pt3_valid.eq(1) +# else + with m.Else(): +# v.pgtbl0 := data; +# v.pt0_valid := '1'; + comb += v.pgtbl0.eq(data) + comb += v.pt0_valid.eq(1) +# end if; +# -- rts == radix tree size, # address bits +# -- being translated +# rts := unsigned('0' & data(62 downto 61) & +# data(7 downto 5)); + # rts == radix tree size, # address bits + # being translated + comb += rts.eq(( + 0 & data[61:63] & data[5:8] + ).as_unsigned()) +# -- mbits == # address bits to index +# -- top level of tree +# mbits := unsigned('0' & data(4 downto 0)); + # mbits == # address bits to index + # top level of tree + comb += mbits.eq(( + 0 & data[0:5] + ).as_unsigned()) +# -- set v.shift to rts so that we can use +# -- finalmask for the segment check # v.shift := rts; # v.mask_size := mbits(4 downto 0); # v.pgbase := data(55 downto 8) & x"00"; - # set v.shift to rts so that we can use finalmask for the - # segment check - comb += v.shift.eq(rts) - comb += v.mask_size.eq(mbits[0:5]) - comb += v.pgbase.eq(data[8:56] & 0x00) -# if mbits = 0 then - with m.If(mbits == 0): + # set v.shift to rts so that we can use + # finalmask for the segment check + comb += v.shift.eq(rts) + comb += v.mask_size.eq(mbits[0:5]) + comb += v.pgbase.eq(data[8:56] & 0x00) +# if mbits = 0 then + with m.If(~mbits): +# v.state := RADIX_FINISH; +# v.invalid := '1'; + comb += v.state.eq(State.RADIX_FINISH) + comb += v.invalid.eq(1) +# else +# v.state := SEGMENT_CHECK; + comb += v.state.eq(State.SEGMENT_CHECK) +# end if; +# end if; + +# if d_in.err = '1' then + with m.If(d_in.err === 1): # v.state := RADIX_FINISH; -# v.invalid := '1'; +# v.badtree := '1'; comb += v.state.eq(State.RADIX_FINISH) - comb += v.invalid.eq(1) -# else -# v.state := SEGMENT_CHECK; - comb += v.state.eq(State.SEGMENT_CHECK) + comb += v.badtree.eq(1) # end if; -# end if; - -# if d_in.err = '1' then - with m.If(d_in.err === 1): -# v.state := RADIX_FINISH; -# v.badtree := '1'; - comb += v.state.eq(State.RADIX_FINISH) - comb += v.badtree.eq(1) -# end if; -# when SEGMENT_CHECK => - with m.Case(State.SEGMENT_CHECK): -# mbits := '0' & r.mask_size; -# v.shift := r.shift + (31 - 12) - mbits; -# nonzero := or(r.addr(61 downto 31) and not finalmask( -# 30 downto 0)); - comb += mbits.eq(0 & r.mask_size) - comb += v.shift.eq(r.shift + (31 -12) - mbits) - comb += nonzero.eq('''TODO wrap in or (?)'''r.addr[31:62] - & (~finalmask[0:31])) -# if r.addr(63) /= r.addr(62) or nonzero = '1' then -# v.state := RADIX_FINISH; -# v.segerror := '1'; - with m.If((r.addr[63] != r.addr[62]) | (nonzero == 1)): - comb += v.state.eq(State.RADIX_FINISH) - comb += v.segerror.eq(1) -# elsif mbits < 5 or mbits > 16 or mbits > -# (r.shift + (31 - 12)) then -# v.state := RADIX_FINISH; -# v.badtree := '1'; - with m.If((mbits < 5) | (mbits > 16) - | (mbits > (r.shift + (31-12)))): - comb += v.state.eq(State.RADIX_FINISH) - comb += v.badtree.eq(1) +# when SEGMENT_CHECK => + with m.Case(State.SEGMENT_CHECK): +# mbits := '0' & r.mask_size; +# v.shift := r.shift + (31 - 12) - mbits; +# nonzero := or(r.addr(61 downto 31) and +# not finalmask(30 downto 0)); + comb += mbits.eq(0 & r.mask_size) + comb += v.shift.eq(r.shift + (31 -12) - mbits) + # TODO need lckl to check this is correct + comb += nonzero.eq(0 | Cat((~finalmask[0:31]), + r.addr[31:62] + )) +# if r.addr(63) /= r.addr(62) or nonzero = '1' then +# v.state := RADIX_FINISH; +# v.segerror := '1'; + with m.If((r.addr[63] != r.addr[62]) + | (nonzero == 1)): + comb += v.state.eq(State.RADIX_FINISH) + comb += v.segerror.eq(1) +# elsif mbits < 5 or mbits > 16 or mbits +# > (r.shift + (31 - 12)) then +# v.state := RADIX_FINISH; +# v.badtree := '1'; + with m.If((mbits < 5) | (mbits > 16) + | (mbits > (r.shift + (31-12)))): + comb += v.state.eq(State.RADIX_FINISH) + comb += v.badtree.eq(1) # else # v.state := RADIX_LOOKUP; - with m.Else(): - comb += v.state.eq(State.RADIX_LOOKUP) + with m.Else(): + comb += v.state.eq(State.RADIX_LOOKUP) # end if; # -# when RADIX_LOOKUP => - with m.Case(State.RADIX_LOOKUP): -# dcreq := '1'; -# v.state := RADIX_READ_WAIT; - comb += dcreq.eq(1) - comb += v.state.eq(State.RADIX_READ_WAIT) +# when RADIX_LOOKUP => + with m.Case(State.RADIX_LOOKUP): +# dcreq := '1'; +# v.state := RADIX_READ_WAIT; + comb += dcreq.eq(1) + comb += v.state.eq(State.RADIX_READ_WAIT) + +# when RADIX_READ_WAIT => + with m.Case(State.RADIX_READ_WAIT): +# if d_in.done = '1' then + with m.If(d_in.done): +# v.pde := data; + comb += v.pde.eq(data) +# -- test valid bit +# if data(63) = '1' then + # test valid bit + with m.If(data[63]): +# -- test leaf bit +# if data(62) = '1' then + # test leaf bit + with m.If(data[62]): +# -- check permissions and RC bits +# perm_ok := '0'; + comb += perm_ok.eq(0) +# if r.priv = '1' or data(3) = '0' then + with m.If((r.priv == 1) | (data[3] == 0)): +# if r.iside = '0' then +# perm_ok := data(1) or (data(2) +# and not r.store); + with m.If(r.iside == 0): + comb += perm_ok.eq( + (data[1] | data[2]) + & (~r.store) + ) +# else + with m.Else(): +# -- no IAMR, so no KUEP support +# -- for now deny execute +# -- permission if cache inhibited +# perm_ok := +# data(0) and not data(5); + # no IAMR, so no KUEP support + # for now deny execute + # permission if cache inhibited + comb += perm_ok.eq( + data[0] & (~data[5]) + ) +# end if; +# end if; -# when RADIX_READ_WAIT => - with m.Case(State.RADIX_READ_WAIT): -# if d_in.done = '1' then - with m.If(d_in.done == 1): -# v.pde := data; - comb += v.pde.eq(data) -# -- test valid bit -# if data(63) = '1' then - # test valid bit - with m.If(data[63] == 1): -# -- test leaf bit -# if data(62) = '1' then - # test leaf bit - with m.If(data[62] == 1): -# -- check permissions and RC bits -# perm_ok := '0'; - comb += perm_ok.eq(0) -# if r.priv = '1' or data(3) = '0' then - with m.If((r.priv == 1) | (data[3] == 0)): -# if r.iside = '0' then -# perm_ok := data(1) or (data(2) and not -# r.store); - with m.If(r.iside == 0): - comb += perm_ok.eq((data[1] | data[2]) - & (~r.store)) +# rc_ok := data(8) and (data(7) or +# not r.store); + comb += rc_ok.eq( + data[8] & + (data[7] | (~r.store)) + ) +# if perm_ok = '1' and rc_ok = '1' then +# v.state := RADIX_LOAD_TLB; + with m.If(perm_ok & rc_ok): + comb += v.state.eq( + State.RADIX_LOAD_TLB + ) # else with m.Else(): -# -- no IAMR, so no KUEP support for now -# -- deny execute permission if cache inhibited -# perm_ok := data(0) and not data(5); - # no IAMR, so no KUEP support for now - # deny execute permission if cache inhibited - comb += perm_ok.eq(data[0] & (~data[5])) +# v.state := RADIX_FINISH; +# v.perm_err := not perm_ok; +# -- permission error takes precedence +# -- over RC error +# v.rc_error := perm_ok; + comb += vl.state.eq( + State.RADIX_FINISH + ) + comb += v.perm_err.eq(~perm_ok) + # permission error takes precedence + # over RC error + comb += v.rc_error.eq(perm_ok) # end if; -# end if; - -# rc_ok := data(8) and (data(7) or not r.store); - comb += rc_ok.eq(data[8] & (data[7] | (~r.store))) -# if perm_ok = '1' and rc_ok = '1' then -# v.state := RADIX_LOAD_TLB; - with m.If(perm_ok == 1 & rc_ok == 1): - comb += v.state.eq(State.RADIX_LOAD_TLB) # else with m.Else(): -# v.state := RADIX_FINISH; -# v.perm_err := not perm_ok; -# -- permission error takes precedence over -# -- RC error -# v.rc_error := perm_ok; - comb += vl.state.eq(State.RADIX_FINISH) - comb += v.perm_err.eq(~perm_ok) - # permission error takes precedence over - # RC error - comb += v.rc_error.eq(perm_ok) +# mbits := unsigned('0' & +# data(4 downto 0)); + comb += mbits.eq((Cat( + data[0:5] + Cont(0b0,1) + )).as_unsigned()) +# if mbits < 5 or mbits > 16 or +# mbits > r.shift then +# v.state := RADIX_FINISH; +# v.badtree := '1'; + with m.If((mbits < 5) & (mbits > 16) | + (mbits > r.shift)): + comb += v.state.eq( + State.RADIX_FINISH + ) + comb += v.badtree.eq(1) +# else + with m.Else(): +# v.shift := v.shift - mbits; +# v.mask_size := mbits(4 downto 0); +# v.pgbase := data(55 downto 8) +# & x"00"; +# v.state := RADIX_LOOKUP; + comb += v.shift.eq(v.shif - mbits) + comb += v.mask_size.eq(mbits[0:5]) + comb += v.pgbase.eq(Cat( + Const(0x00, 2), + mbits[8:56]) + ) + comb += v.state.eq( + State.RADIX_LOOKUP + ) +# end if; # end if; # else with m.Else(): -# mbits := unsigned('0' & data(4 downto 0)); - comb += mbits.eq((0 & data[0:5]).as_unsigned()) -# if mbits < 5 or mbits > 16 or mbits > r.shift then -# v.state := RADIX_FINISH; -# v.badtree := '1'; - with m.If((mbits < 5) & (mbits > 16) | - (mbits > r.shift)): - comb += v.state.eq(State.RADIX_FINISH) - comb += v.badtree.eq(1) -# else - with m.Else(): -# v.shift := v.shift - mbits; -# v.mask_size := mbits(4 downto 0); -# v.pgbase := data(55 downto 8) & x"00"; -# v.state := RADIX_LOOKUP; - comb += v.shift.eq(v.shif - mbits) - comb += v.mask_size.eq(mbits[0:5]) - comb += v.pgbase.eq(mbits[8:56] & 0x00) - comb += v.state.eq(State.RADIX_LOOKUP) -# end if; +# -- non-present PTE, generate a DSI +# v.state := RADIX_FINISH; +# v.invalid := '1'; + # non-present PTE, generate a DSI + comb += v.state.eq(State.RADIX_FINISH) + comb += v.invalid.eq(1) # end if; -# else - with m.Else(): -# -- non-present PTE, generate a DSI +# end if; + +# if d_in.err = '1' then + with m.If(d_in.err): # v.state := RADIX_FINISH; -# v.invalid := '1'; - # non-present PTE, generate a DSI +# v.badtree := '1'; comb += v.state.eq(State.RADIX_FINISH) - comb += v.invalid.eq(1) + comb += v.badtree.eq(1) # end if; -# end if; -# if d_in.err = '1' then - with m.If(d_in.err == 1): -# v.state := RADIX_FINISH; -# v.badtree := '1'; - comb += v.state.eq(State.RADIX_FINISH) - comb += v.badtree.eq(1) -# end if; +# when RADIX_LOAD_TLB => + with m.Case(State.RADIX_LOAD_TLB): +# tlb_load := '1'; + comb += tlb_load.eq(1) +# if r.iside = '0' then + with m.If(~r.iside): +# dcreq := '1'; +# v.state := TLB_WAIT; + comb += dcreq.eq(1) + comb += v.state.eq(State.TLB_WAIT) +# else + with m.Else(): +# itlb_load := '1'; +# v.state := IDLE; + comb += itlb_load.eq(1) + comb += v.state.eq(State.IDLE) +# end if; -# when RADIX_LOAD_TLB => - with m.Case(State.RADIX_LOAD_TLB): -# tlb_load := '1'; - comb += tlb_load.eq(1) -# if r.iside = '0' then - with m.If(r.iside == 0): -# dcreq := '1'; -# v.state := TLB_WAIT; - comb += dcreq.eq(1) - comb += v.state.eq(State.TLB_WAIT) -# else - with m.Else(): -# itlb_load := '1'; +# when RADIX_FINISH => # v.state := IDLE; - comb += itlb_load.eq(1) + with m.Case(State.RADIX_FINISH): +# v.state := IDLE comb += v.state.eq(State.IDLE) -# end if; - -# when RADIX_FINISH => -# v.state := IDLE; - with m.Case(State.RADIX_FINISH): - comb += v.state.eq(State.IDLE) # end case; # # if v.state = RADIX_FINISH or (v.state = RADIX_LOAD_TLB # and r.iside = '1') then - with m.If(v.state == State.RADIX_FINISH | (v.state == - State.RADIX_LOAD_TLB & r.iside == 1)) -# v.err := v.invalid or v.badtree or v.segerror or v.perm_err -# or v.rc_error; + with m.If(v.state == State.RADIX_FINISH + | (v.state == State.RADIX_LOAD_TLB & r.iside) + ) +# v.err := v.invalid or v.badtree or v.segerror +# or v.perm_err or v.rc_error; # v.done := not v.err; comb += v.err.eq(v.invalid | v.badtree | v.segerror | v.perm_err | v.rc_error) @@ -901,12 +996,12 @@ class AddrShifter(Elaboratable): # end if; # if r.addr(63) = '1' then + with m.If(r.addr[63]): # effpid := x"00000000"; - with m.If(r.addr[63] == 1): - comb += effpid.eq(0x00000000) + comb += effpid.eq(Const(0x00000000,1)) # else -# effpid := r.pid; with m.Else(): +# effpid := r.pid; comb += effpid.eq(r.pid) # end if; # prtable_addr := x"00" & r.prtbl(55 downto 36) & @@ -914,42 +1009,73 @@ class AddrShifter(Elaboratable): # 23 downto 0)) or (effpid(31 downto 8) and # finalmask(23 downto 0))) & effpid(7 downto 0) # & "0000"; - comb += prtable_addr.eq(0x00 & r.prtble[36:56] & - ((r.prtble[12:36] & (~finalmask[0:24])) - | effpid[8:32] & finalmask[0:24]) - & effpid[0:8] & 0x0000) + comb += prtable_addr.eq( + Cat( + Cat( + Cat( + Cat(Const(0b000, 4), effpid[0:8]), + ( + (r.prtble[12:36] & (~finalmask[0:24])) + | effpid[8:32] & finalmask[0:24] + ) + ), + r.prtbl[36:56] + ), + Const(0x00, 2) + ) + ) # pgtable_addr := x"00" & r.pgbase(55 downto 19) & # ((r.pgbase(18 downto 3) and not mask) or # (addrsh and mask)) & "000"; - comb += pgtable_addr.eq(0x00 & r.pgbase[19:56] & ((r.pgbase[3:19] - & (~mask)) | (addrsh & mask)) & 0x000) + comb += pgtable_addr.eq( + Cat( + Cat( + Const(0b000, 3), + ( + (r.pgbase[3:19] & (~mask)) + | (addrsh & mask) + ) + ), + Const(0x00, 2) + ) + ) # pte := x"00" & ((r.pde(55 downto 12) and not finalmask) or # (r.addr(55 downto 12) and finalmask)) & r.pde(11 downto 0); - comb += pte.eq(0x00 & ((r.pde[12:56] & (~finalmask)) - | (r.addr[12:56] & finalmask)) & r.pde[0:12]) + comb += pte.eq( + Cat( + Cat( + r.pde[0:12], + ( + (r.pde[12:56] & (~finalmask)) + | (r.addr[12:56] & finalmask) + ) + ), + Const(0x00, 2) + ) + ) # -- update registers # rin <= v; # update registers - rin.eq(v - ) + rin.eq(v) + # -- drive outputs # if tlbie_req = '1' then # drive outputs - with m.If(tlbie_req == 1): + with m.If(tlbie_req): # addr := r.addr; # tlb_data := (others => '0'); comb += addr.eq(r.addr) comb += tlb_data.eq('''TODO ()others => '0') ''') # elsif tlb_load = '1' then - with m.If(tlb_load == 1): + with m.If(tlb_load): # addr := r.addr(63 downto 12) & x"000"; # tlb_data := pte; - comb += addr.eq(r.addr[12:64] & 0x000) + comb += addr.eq(Cat(Const(0x000, 3), r.addr[12:64])) # elsif prtbl_rd = '1' then - with m.If(prtbl_rd == 1): + with m.If(prtbl_rd): # addr := prtable_addr; # tlb_data := (others => '0'); comb += addr.eq(prtable_addr) @@ -1002,4 +1128,4 @@ class AddrShifter(Elaboratable): comb += i_out.pte.eq(tlb_data) # end process; -#end; +# end; -- 2.30.2