lib/HDLRuby/std/memory.rb in HDLRuby-2.2.17 vs lib/HDLRuby/std/memory.rb in HDLRuby-2.3.0

- old
+ new

@@ -168,13 +168,194 @@ end end end +# Flexible ROM memory of +size+ elements of +typ+ typ, syncrhonized on +clk+ +# (positive and negative edges) and reset on +rst+. +# At each rising edge of +clk+ a read and a write is guaranteed to be +# completed provided they are triggered. +# +br_rsts+ are reset names on the branches, if not given, a reset input +# is added and connected to rst. +# The content of the ROM is passed through +content+ argument. +# +# NOTE: +# +# * such memories uses the following ports: +# - trig_r: read access trigger (output) +# - trig_w: write access trigger (output) +# - dbus_r: read data bus (input) +# - dbus_w: write data bus (output) +# +# * The following branches are possible (only one read and one write can +# be used per channel) +# - raddr: read by address, this channel adds the following port: +# abus_r: read address bus (output) +# - waddr: read by address, this channel adds the following port: +# abus_w: write address bus (output) +# - rinc: read by automatically incremented address. +# - winc: write by automatically incremented address. +# - rdec: read by automatically decremented address. +# - wdec: write by automatically decremented address. +# - rque: read in queue mode: automatically incremented address ensuring +# the read address is always different from the write address. +# - wque: write in queue mode: automatically incremented address ensuring +# the write address is always differnet from the read address. +# +HDLRuby::High::Std.channel(:mem_rom) do |typ,size,clk,rst,content, + br_rsts = {}| + # Ensure typ is a type. + typ = typ.to_type + # Ensure size in an integer. + size = size.to_i + # Compute the address bus width from the size. + awidth = (size-1).width + # Process the table of reset mapping for the branches. + # Ensures br_srts is a hash. + br_rsts = br_rsts.to_hash + # Declare the control signals. + # Access trigger. + inner :trig_r + # Data bus + typ.inner :dbus_r + # Address bus (or simply register) + [awidth].inner :abus_r + # Declare the ROM with its inner content. + # typ[-size].constant mem: content.map { |val| val.to_expr } + typ[-size].constant mem: content + # Processes handling the memory access. + par(clk.negedge) do + dbus_r <= mem[abus_r] + end + + # The address branches. + # Read with address + brancher(:raddr) do + reader_output :trig_r, :abus_r + reader_input :dbus_r + if br_rsts[:raddr] then + rst_name = br_rsts[:raddr].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,addr,target| + # By default the read trigger is 0. + top_block.unshift { trig_r <= 0 } + # The read procedure. + rst = send(rst_name) + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(trig_r == 1) do + # The trigger was previously set, read ok. + target <= dbus_r + trig_r <= 0 + blk.call if blk + end + helse do + # Prepare the read. + abus_r <= addr + trig_r <= 1 + end + end + end + end + end + + # The increment branches. + # Read with increment + brancher(:rinc) do + reader_output :trig_r, :abus_r + reader_input :dbus_r + if br_rsts[:rinc] then + rst_name = br_rsts[:rinc].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst==1) { abus_r <= -1 } + # Reset so switch of the access trigger. + trig_r <= 0 + end + # The read procedure. + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(trig_r == 1) do + # The trigger was previously set, read ok. + target <= dbus_r + blk.call if blk + end + # Prepare the read. + abus_r <= abus_r + 1 + trig_r <= 1 + end + end + end + end + + # The decrement branches. + # Read with increment + brancher(:rdec) do + reader_output :trig_r, :abus_r + reader_input :dbus_r + if br_rsts[:rdec] then + rst_name = br_rsts[:rdec].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst==1) { abus_r <= 0 } + # Reset so switch of the access trigger. + trig_r <= 0 + end + # The read procedure. + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(trig_r == 1) do + # The trigger was previously set, read ok. + target <= dbus_r + blk.call if blk + end + # Prepare the read. + abus_r <= abus_r - 1 + trig_r <= 1 + end + end + end + end + +end + + + + + # Flexible dual-edge memory with distinct read and write ports of +size+ # elements of +typ+ typ, syncrhonized on +clk+ (positive and negative edges) # and reset on +rst+. # At each rising edge of +clk+ a read and a write is guaranteed to be # completed provided they are triggered. @@ -211,32 +392,36 @@ size = size.to_i # Compute the address bus width from the size. awidth = (size-1).width # Process the table of reset mapping for the branches. # puts "first br_rsts=#{br_rsts}" - if br_rsts.is_a?(Array) then - # It is a list, convert it to a hash with the following order: - # raddr, waddr, rinc, winc, rdec, wdec, rque, wque - # If there is only two entries they will be duplicated and mapped - # as follows: - # [raddr,waddr], [rinc,winc], [rdec,wdec], [rque,wque] - # If there is only one entry it will be duplicated and mapped as - # follows: - # raddr, rinc, rdec, rque - if br_rsts.size == 2 then - br_rsts = br_rsts * 4 - elsif br_rsts.size == 1 then - br_rsts = br_rsts * 8 - end - br_rsts = { raddr: br_rsts[0], waddr: br_rsts[1], - rinc: br_rsts[2], winc: br_rsts[3], - rdec: br_rsts[4], wdec: br_rsts[5], - rque: br_rsts[6], wque: br_rsts[6] } - end - unless br_rsts.respond_to?(:[]) - raise "Invalid reset mapping description: #{br_rsts}" - end + # if br_rsts.is_a?(Array) then + # # It is a list, convert it to a hash with the following order: + # # raddr, waddr, rinc, winc, rdec, wdec, rque, wque + # # When not specified the reset is +rst+ by default. + # # If there is only two entries they will be duplicated and mapped + # # as follows: + # # [raddr,waddr], [rinc,winc], [rdec,wdec], [rque,wque] + # # If there is only one entry it will be duplicated and mapped as + # # follows: + # # raddr, rinc, rdec, rque + # if br_rsts.size == 2 then + # br_rsts = br_rsts * 4 + # elsif br_rsts.size == 1 then + # br_rsts = br_rsts * 8 + # end + # br_rsts = { raddr: br_rsts[0], waddr: br_rsts[1], + # rinc: br_rsts[2], winc: br_rsts[3], + # rdec: br_rsts[4], wdec: br_rsts[5], + # rque: br_rsts[6], wque: br_rsts[6] } + # end + # unless br_rsts.respond_to?(:[]) + # raise "Invalid reset mapping description: #{br_rsts}" + # end + # + # Ensures br_srts is a hash. + br_rsts = br_rsts.to_hash # Declare the control signals. # Access triggers. inner :trig_r, :trig_w # Data buses @@ -340,11 +525,11 @@ end # Defines the read procedure at address +addr+ # using +target+ as target of access result. reader do |blk,target| - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst==1) { abus_r <= -1 } # Reset so switch of the access trigger. @@ -380,11 +565,11 @@ # puts "rst_name=#{rst_name}" # Defines the read procedure at address +addr+ # using +target+ as target of access result. writer do |blk,target| - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst == 1) { abus_w <= -1 } # Reset so switch of the access trigger. @@ -418,11 +603,11 @@ end # Defines the read procedure at address +addr+ # using +target+ as target of access result. reader do |blk,target| - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst==1) { abus_r <= 0 } # Reset so switch of the access trigger. @@ -458,11 +643,11 @@ # puts "rst_name=#{rst_name}" # Defines the read procedure at address +addr+ # using +target+ as target of access result. writer do |blk,target| - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst == 1) { abus_w <= 0 } # Reset so switch of the access trigger. @@ -673,11 +858,11 @@ # Defines the read procedure at address +addr+ # using +target+ as target of access result. reader do |blk,target| regs = size.times.map {|i| send(:"reg_#{i}") } - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst==1) { abus_r <= 0 } end @@ -712,11 +897,11 @@ # Defines the write procedure at address +addr+ # using +target+ as target of access result. writer do |blk,target| regs = size.times.map {|i| send(:"reg_#{i}") } - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst==1) { abus_w <= 0 } end @@ -753,11 +938,11 @@ # Defines the read procedure at address +addr+ # using +target+ as target of access result. reader do |blk,target| regs = size.times.map {|i| send(:"reg_#{i}") } - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst==1) { abus_r <= -1 } end @@ -792,11 +977,11 @@ # Defines the write procedure at address +addr+ # using +target+ as target of access result. writer do |blk,target| regs = size.times.map {|i| send(:"reg_#{i}") } - # By default the read trigger is 0. + # On reset the read trigger is 0. rst = send(rst_name) top_block.unshift do # Initialize the address so that the next access is at address 0. hif(rst==1) { abus_w <= -1 } end @@ -815,5 +1000,790 @@ end end end end + + + + +# Multi-bank memory combining several dual-edge memories of +nbanks+ banks +# of +size+ elements of +typ+ typ, syncrhonized on +clk+ (positive and +# negative edges) and reset on +rst+. +# at each rising edge of +clk+ a read and a write is guaranteed to be +# completed provided they are triggered. +# +br_rsts+ are reset names on the branches, if not given, a reset input +# is added and connected to rst. +# +# NOTE: +# +# * such memories uses the following ports: +# - trig_r: read access trigger (output) +# - trig_w: write access trigger (output) +# - dbus_r: read data bus (input) +# - dbus_w: write data bus (output) +# +# * The following branches are possible (only one read and one write can +# be used per channel) +# - raddr: read by address, this channel adds the following port: +# abus_r: read address bus (output) +# - waddr: read by address, this channel adds the following port: +# abus_w: write address bus (output) +# - rinc: read by automatically incremented address. +# - winc: write by automatically incremented address. +# - rdec: read by automatically decremented address. +# - wdec: write by automatically decremented address. +# - rque: read in queue mode: automatically incremented address ensuring +# the read address is always different from the write address. +# - wque: write in queue mode: automatically incremented address ensuring +# the write address is always differnet from the read address. +HDLRuby::High::Std.channel(:mem_bank) do |typ,nbanks,size,clk,rst,br_rsts = {}| + # Ensure typ is a type. + typ = typ.to_type + # Ensure size in an integer. + size = size.to_i + # Compute the address bus width from the size. + awidth = (size*nbanks-1).width + awidth_b = (size-1).width # Bank width + # Ensures br_srts is a hash. + br_rsts = br_rsts.to_hash + + # The global buses and control signals. + [awidth].inner :abus_r, :abus_w + typ.inner :dbus_r, :dbus_w + inner :trig_r, :trig_w + + # For each bank. + nbanks.times do |id| + # Declare the control signals. + # Access triggers. + inner :"trig_r_#{id}", :"trig_w_#{id}" + # Data buses + typ.inner :"dbus_r_#{id}", :"dbus_w_#{id}" + # Address buses (or simply registers) + [awidth_b].inner :"abus_r_#{id}", :"abus_w_#{id}" + + # Declare the memory content. + typ[-size].inner :"mem_#{id}" + + # Processes handling the memory access. + par(clk.negedge) do + send(:"dbus_r_#{id}") <= send(:"mem_#{id}")[send(:"abus_r_#{id}")] + hif(trig_w & ((abus_w % nbanks) == id)) do + send(:"mem_#{id}")[send(:"abus_w_#{id}")] <= dbus_w + end + helsif(send(:"trig_w_#{id}")) do + send(:"mem_#{id}")[send(:"abus_w_#{id}")] <= send(:"dbus_w_#{id}") + end + end + end + # Interconnect the buses and triggers + nbanks.times do |id| + send(:"abus_r_#{id}") <= abus_r / nbanks + send(:"abus_w_#{id}") <= abus_w / nbanks + end + par do + # By default triggers are off. + nbanks.times do |id| + send(:"trig_w_#{id}") <= 0 + send(:"trig_r_#{id}") <= 0 + end + # Set the read address bus and trigger if required. + hcase(abus_r % nbanks) + nbanks.times do |id| + hwhen(id) do + dbus_r <= send(:"dbus_r_#{id}") + send(:"trig_r_#{id}") <= trig_r + end + end + end + + + # The address branches. + # Read with address + brancher(:raddr) do + reader_output :trig_r, :abus_r + reader_input :dbus_r + if br_rsts[:raddr] then + rst_name = br_rsts[:raddr].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,addr,target| + # By default the read trigger is 0. + top_block.unshift { trig_r <= 0 } + # The read procedure. + rst = send(rst_name) + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(trig_r == 1) do + # The trigger was previously set, read ok. + target <= dbus_r + trig_r <= 0 + blk.call if blk + end + helse do + # Prepare the read. + abus_r <= addr + trig_r <= 1 + end + end + end + end + end + + # Write with address + brancher(:waddr) do + writer_output :trig_w, :abus_w, :dbus_w + if br_rsts[:waddr] then + rst_name = br_rsts[:waddr].to_sym + else + rst_name = rst.name + writer_input rst_name + end + # puts "br_rsts=#{br_rsts}" + # puts "rst_name=#{rst_name}" + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + writer do |blk,addr,target| + # By default the read trigger is 0. + top_block.unshift { trig_w <= 0 } + # The write procedure. + rst = send(rst_name) + par do + hif(rst == 0) do + # No reset, so can perform the write. + hif(trig_w == 1) do + # The trigger was previously set, write ok. + blk.call if blk + end + # Prepare the write. + abus_w <= addr + trig_w <= 1 + dbus_w <= target + end + end + end + end + + # The increment branches. + # Read with increment + brancher(:rinc) do + reader_output :trig_r, :abus_r + reader_input :dbus_r + if br_rsts[:rinc] then + rst_name = br_rsts[:rinc].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst==1) { abus_r <= -1 } + # Reset so switch of the access trigger. + trig_r <= 0 + end + # The read procedure. + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(trig_r == 1) do + # The trigger was previously set, read ok. + target <= dbus_r + blk.call if blk + end + # Prepare the read. + abus_r <= abus_r + 1 + trig_r <= 1 + end + end + end + end + + # Write with address + brancher(:winc) do + writer_output :trig_w, :abus_w, :dbus_w + if br_rsts[:winc] then + rst_name = br_rsts[:winc].to_sym + else + rst_name = rst.name + writer_input rst_name + end + # puts "br_rsts=#{br_rsts}" + # puts "rst_name=#{rst_name}" + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + writer do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst == 1) { abus_w <= -1 } + # Reset so switch of the access trigger. + trig_w <= 0 + end + # The write procedure. + par do + hif(rst == 0) do + # No reset, so can perform the write. + blk.call if blk + # Prepare the write. + abus_w <= abus_w + 1 + trig_w <= 1 + dbus_w <= target + end + end + end + end + + # The decrement branches. + # Read with increment + brancher(:rdec) do + reader_output :trig_r, :abus_r + reader_input :dbus_r + if br_rsts[:rdec] then + rst_name = br_rsts[:rdec].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst==1) { abus_r <= 0 } + # Reset so switch of the access trigger. + trig_r <= 0 + end + # The read procedure. + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(trig_r == 1) do + # The trigger was previously set, read ok. + target <= dbus_r + blk.call if blk + end + # Prepare the read. + abus_r <= abus_r - 1 + trig_r <= 1 + end + end + end + end + + # Write with address + brancher(:wdec) do + writer_output :trig_w, :abus_w, :dbus_w + if br_rsts[:wdec] then + rst_name = br_rsts[:wdec].to_sym + else + rst_name = rst.name + writer_input rst_name + end + # puts "br_rsts=#{br_rsts}" + # puts "rst_name=#{rst_name}" + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + writer do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst == 1) { abus_w <= 0 } + # Reset so switch of the access trigger. + trig_w <= 0 + end + # The write procedure. + par do + hif(rst == 0) do + # No reset, so can perform the write. + blk.call if blk + # Prepare the write. + abus_w <= abus_w - 1 + trig_w <= 1 + dbus_w <= target + end + end + end + end + + + # Declare the branchers for accessing directly the banks. + nbanks.times do |id| + # Read with address. + brancher(:"raddr_#{id}") do + reader_output :"trig_r_#{id}", :"abus_r_#{id}" + reader_input :"dbus_r_#{id}" + if br_rsts[:"raddr_#{id}"] then + rst_name = br_rsts[:"raddr_#{id}"].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,addr,target| + # By default the read trigger is 0. + top_block.unshift { send(:"trig_r_#{id}") <= 0 } + # The read procedure. + rst = send(rst_name) + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(send(:"trig_r_#{id}") == 1) do + # The trigger was previously set, read ok. + target <= send(:"dbus_r_#{id}") + send(:"trig_r_#{id}") <= 0 + blk.call if blk + end + helse do + # Prepare the read. + send(:"abus_r_#{id}") <= addr + send(:"trig_r_#{id}") <= 1 + end + end + end + end + end + + # Write with address + brancher(:"waddr_#{id}") do + writer_output :"trig_w_#{id}", :"abus_w_#{id}", :"dbus_w_#{id}" + if br_rsts[:"waddr_#{id}"] then + rst_name = br_rsts[:"waddr_#{id}"].to_sym + else + rst_name = rst.name + writer_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + writer do |blk,addr,target| + # By default the read trigger is 0. + top_block.unshift { send(:"trig_w_#{id}") <= 0 } + # The write procedure. + rst = send(rst_name) + par do + hif(rst == 0) do + # No reset, so can perform the write. + hif(send(:"trig_w_#{id}") == 1) do + # The trigger was previously set, write ok. + blk.call if blk + end + # Prepare the write. + send(:"abus_w_#{id}") <= addr + send(:"trig_w_#{id}") <= 1 + send(:"dbus_w_#{id}") <= target + end + end + end + end + + # The increment branches. + # Read with increment + brancher(:"rinc_#{id}") do + reader_output :"trig_r_#{id}", :"abus_r_#{id}" + reader_input :"dbus_r_#{id}" + if br_rsts[:"rinc_#{id}"] then + rst_name = br_rsts[:"rinc_#{id}"].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst==1) { send(:"abus_r_#{id}") <= -1 } + # Reset so switch of the access trigger. + send(:"trig_r_#{id}") <= 0 + end + # The read procedure. + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(send(:"trig_r_#{id}") == 1) do + # The trigger was previously set, read ok. + target <= send(:"dbus_r_#{id}") + blk.call if blk + end + # Prepare the read. + send(:"abus_r_#{id}") <= send(:"abus_r_#{id}") + 1 + send(:"trig_r_#{id}") <= 1 + end + end + end + end + + # Write with address + brancher(:"winc_#{id}") do + writer_output :"trig_w_#{id}", :"abus_w_#{id}", :"dbus_w_#{id}" + if br_rsts[:"winc_#{id}"] then + rst_name = br_rsts[:"winc_#{id}"].to_sym + else + rst_name = rst.name + writer_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + writer do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst == 1) { send(:"abus_w_#{id}") <= -1 } + # Reset so switch of the access trigger. + send(:"trig_w_#{id}") <= 0 + end + # The write procedure. + par do + hif(rst == 0) do + # No reset, so can perform the write. + blk.call if blk + # Prepare the write. + send(:"abus_w_#{id}") <= send(:"abus_w_#{id}") + 1 + send(:"trig_w_#{id}") <= 1 + send(:"dbus_w_#{id}") <= target + end + end + end + end + + # The decrement branches. + # Read with increment + brancher(:"rdec_#{id}") do + reader_output :"trig_r_#{id}", :"abus_r_#{id}" + reader_input :"dbus_r_#{id}" + if br_rsts[:"rdec_#{id}"] then + rst_name = br_rsts[:"rdec_#{id}"].to_sym + else + rst_name = rst.name + reader_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + reader do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst==1) { send(:"abus_r_#{id}") <= 0 } + # Reset so switch of the access trigger. + send(:"trig_r_#{id}") <= 0 + end + # The read procedure. + par do + hif(rst == 0) do + # No reset, so can perform the read. + hif(send(:"trig_r_#{id}") == 1) do + # The trigger was previously set, read ok. + target <= send(:"dbus_r_#{id}") + blk.call if blk + end + # Prepare the read. + send(:"abus_r_#{id}") <= send(:"abus_r_#{id}") - 1 + send(:"trig_r_#{id}") <= 1 + end + end + end + end + + # Write with address + brancher(:"wdec_#{id}") do + writer_output :"trig_w_#{id}", :"abus_w_#{id}", :"dbus_w_#{id}" + if br_rsts[:"wdec_#{id}"] then + rst_name = br_rsts[:"wdec_#{id}"].to_sym + else + rst_name = rst.name + writer_input rst_name + end + + # Defines the read procedure at address +addr+ + # using +target+ as target of access result. + writer do |blk,target| + # On reset the read trigger is 0. + rst = send(rst_name) + top_block.unshift do + # Initialize the address so that the next access is at address 0. + hif(rst == 1) { send(:"abus_w_#{id}") <= 0 } + # Reset so switch of the access trigger. + trig_w <= 0 + end + # The write procedure. + par do + hif(rst == 0) do + # No reset, so can perform the write. + blk.call if blk + # Prepare the write. + send(:"abus_w_#{id}") <= send(:"abus_w_#{id}") - 1 + send(:"trig_w_#{id}") <= 1 + send(:"dbus_w_#{id}") <= target + end + end + end + end + end + +end + +# HDLRuby::High::Std.channel(:mem_bank) do |typ,nbanks,size,clk,rst,br_rsts = {}| +# # Ensure typ is a type. +# typ = typ.to_type +# # Ensure nbank is an integer. +# nbanks = nbanks.to_i +# # Ensure size in an integer. +# size = size.to_i +# # Compute the address bus width from the size. +# awidth = (size-1).width +# # # Process the table of reset mapping for the branches. +# # # puts "first br_rsts=#{br_rsts}" +# # if br_rsts.is_a?(Array) then +# # # It is a list, convert it to a hash with the following order: +# # # raddr, waddr, rinc, winc, rdec, wdec, rque, wque +# # # If there is only two entries they will be duplicated and mapped +# # # as follows: +# # # [raddr,waddr], [rinc,winc], [rdec,wdec], [rque,wque] +# # # If there is only one entry it will be duplicated and mapped as +# # # follows: +# # # raddr, rinc, rdec, rque +# # if br_rsts.size == 2 then +# # br_rsts = br_rsts * 4 +# # elsif br_rsts.size == 1 then +# # br_rsts = br_rsts * 8 +# # end +# # br_rsts = { raddr: br_rsts[0], waddr: br_rsts[1], +# # rinc: br_rsts[2], winc: br_rsts[3], +# # rdec: br_rsts[4], wdec: br_rsts[5], +# # rque: br_rsts[6], wque: br_rsts[6] } +# # end +# # unless br_rsts.respond_to?(:[]) +# # raise "Invalid reset mapping description: #{br_rsts}" +# # end +# # Ensures br_rsts is a hash. +# br_rsts = br_rsts.to_hash +# +# # Declares the banks. +# banks = nbanks.times.map do |id| +# # Extract the resets corresponding to the bank. +# cur_br_rsts = {} +# br_rsts.each do |k,v| +# num = k.to_s[/\d+$/] +# if num && num.to_i == id then +# cur_br_rsts[k.to_s.chomp[num]] = v +# end +# end +# # Declare the bank. +# mem_dual(typ,size,clk,rst, cur_br_rsts).(HDLRuby.uniq_name) +# end +# +# # Declare the branchers for accessing directly the banks. +# banks.each_with_index do |bank,id| +# brancher(id,bank) +# end +# +# # Generate the gobal access to the memory. +# +# # The address branches. +# # Read with address +# brancher(:raddr) do +# # Create the read branch for each bank. +# bank_brs = banks.map do |bank| +# bank.branch(:raddr).inner HDLRuby.uniq_name +# end +# # Defines the read procedure at address +addr+ +# # using +target+ as target of access result. +# reader do |blk,addr,target| +# # Select the bank depending on the address. +# hcase(addr / nbanks) +# nbanks.times do |i| +# hwhen(i) do +# bank_brs[i].read(addr % nbanks,target,&blk) +# end +# end +# end +# end +# # Write with address +# brancher(:waddr) do +# # Create the write branch for each bank. +# bank_brs = banks.map do |bank| +# bank.branch(:waddr).inner HDLRuby.uniq_name +# end +# # Defines the read procedure at address +addr+ +# # using +target+ as target of access result. +# writer do |blk,addr,target| +# # Select the bank depending on the address. +# hcase(addr / nbanks) +# nbanks.times do |i| +# hwhen(i) do +# bank_brs[i].write(addr % nbanks,target,&blk) +# end +# end +# end +# end +# +# +# # Address buses (or simply registers) for increment/decrement accesses +# [awidth].inner :abus_r, :abus_w +# +# # The increment branches. +# # Read with increment +# brancher(:rinc) do +# reader_output :abus_r +# if br_rsts[:rinc] then +# rst_name = br_rsts[:rinc].to_sym +# else +# rst_name = rst.name +# reader_input rst_name +# end +# # Create the write branch for each bank. +# bank_brs = banks.map do |bank| +# bank.branch(:raddr).inner HDLRuby.uniq_name +# end +# +# # Defines the read procedure at address +addr+ +# # using +target+ as target of access result. +# reader do |blk,target| +# # On reset the read trigger is 0. +# rst = send(rst_name) +# top_block.unshift do +# # Initialize the address so that the next access is at address 0. +# hif(rst==1) { abus_r <= 0 } +# end +# # Select the bank depending on the address. +# hcase(abus_r / nbanks) +# nbanks.times do |i| +# hwhen(i) do +# bank_brs[i].read(abus_r % nbanks,target) do +# abus_r <= abus_r + 1 +# blk.call +# end +# end +# end +# end +# end +# # Write with increment +# brancher(:winc) do +# reader_output :abus_w +# if br_rsts[:winc] then +# rst_name = br_rsts[:winc].to_sym +# else +# rst_name = rst.name +# writer_input rst_name +# end +# # Create the write branch for each bank. +# bank_brs = banks.map do |bank| +# bank.branch(:waddr).inner HDLRuby.uniq_name +# end +# +# # Defines the read procedure at address +addr+ +# # using +target+ as target of access result. +# writer do |blk,target| +# # On reset the read trigger is 0. +# rst = send(rst_name) +# top_block.unshift do +# # Initialize the address so that the next access is at address 0. +# hif(rst==1) { abus_w <= 0 } +# end +# # Select the bank depending on the address. +# hcase(abus_w / nbanks) +# nbanks.times do |i| +# hwhen(i) do +# bank_brs[i].read(abus_w % nbanks,target) do +# abus_w <= abus_w + 1 +# blk.call +# end +# end +# end +# end +# end +# +# # The decrement branches. +# # Read with decrement +# brancher(:rdec) do +# reader_output :abus_r +# if br_rsts[:rdec] then +# rst_name = br_rsts[:rdec].to_sym +# else +# rst_name = rst.name +# reader_input rst_name +# end +# +# # Defines the read procedure at address +addr+ +# # using +target+ as target of access result. +# reader do |blk,target| +# # On reset the read trigger is 0. +# rst = send(rst_name) +# top_block.unshift do +# # Initialize the address so that the next access is at address 0. +# hif(rst==1) { abus_r <= 0 } +# end +# # Select the bank depending on the address. +# hcase(abus_r / nbanks) +# nbanks.times do |i| +# hwhen(i) do +# banks[i].read(abus_r % nbanks,target) do +# abus_r <= abus_r + 1 +# blk.call +# end +# end +# end +# end +# end +# # Write with decrement +# brancher(:wdec) do +# reader_output :abus_w +# if br_rsts[:wdec] then +# rst_name = br_rsts[:wdec].to_sym +# else +# rst_name = rst.name +# writer_input rst_name +# end +# +# # Defines the read procedure at address +addr+ +# # using +target+ as target of access result. +# writer do |blk,target| +# # On reset the read trigger is 0. +# rst = send(rst_name) +# top_block.unshift do +# # Initialize the address so that the next access is at address 0. +# hif(rst==1) { abus_w <= 0 } +# end +# # Select the bank depending on the address. +# hcase(abus_w / nbanks) +# nbanks.times do |i| +# hwhen(i) do +# banks[i].read(abus_w % nbanks,target) do +# abus_w <= abus_w + 1 +# blk.call +# end +# end +# end +# end +# end +# +# end