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