Skip to content

Instantly share code, notes, and snippets.

@tomoasleep
Last active December 31, 2015 07:39
Show Gist options
  • Save tomoasleep/7955555 to your computer and use it in GitHub Desktop.
Save tomoasleep/7955555 to your computer and use it in GitHub Desktop.
パイプラインの各ステージごとの命令デコーダを作るスクリプトを書いた。.vhd.erbたのしい!
require 'yaml'
require 'erb'
require 'forwardable'
class Hash
def except_keys_in(*keys)
hash_clone = self.clone
keys.each { |k| hash_clone.delete k }
hash_clone
end
end
class DecoderMaker
def initialize(yaml_path, stage_name)
@yaml = YAML.load(File.read(yaml_path))
@stages = @yaml['has_state'].map { |stage| "#{stage}_state" }
@orders = @yaml['order']
@dependencies = @yaml['dependencies']
@stage_idx = @stages.find_index("#{stage_name}_state")
unless @stage_idx
raise "stage name'#{stage_name}_state' isnot exist in [#{@stages.join(', ')}]"
end
end
def run
parse_orders('result', @orders)
@order_groups = @order_groups_each_stage.transpose[@stage_idx]
@result_group = @order_groups.last
puts to_vhdl
end
private
def parse_orders(group_name, orders)
settings = orders['settings']
order_type = "#{settings['type']}_type"
order_prefix = settings['prefix']
_, order_state_maps =
orders
.except_keys_in('settings')
.reverse_each
.reduce(
[Array.new(@stages.size, 'nop'), {}]
) do |(last_s, os_maps), (order, v)|
states = case v
when Hash
parse_orders(order, v)
when Array
@stages.zip(v).map { |stage, state| "#{stage}_#{state}" }
when String
v
else
last_s
end
order_name = (order == 'others') ? order : "#{order_prefix}_#{order}"
[states, os_maps.merge(order_name => states)]
end
signals = @stages.map { |stage| "#{stage}_#{group_name}" }
signal_types = @stages.map { |stage| "#{stage}_type" }
@order_groups_each_stage ||= []
@order_groups_each_stage << OrderGroup
.new_each_stage(signals, signal_types, order_state_maps, order_type)
signals
end
def to_vhdl
DecoderPresenter.new(
@order_groups, @result_group, @stages[@stage_idx], @dependencies).to_vhdl
end
end
class DecoderPresenter
TempletePath = File.expand_path('../templetes/decoder.vhd.erb', __FILE__)
attr_reader :dependencies
def initialize(order_groups, result_group, stage, dependencies)
@order_groups = order_groups
@result_group = result_group
@stage = stage
@dependencies = dependencies
end
def groups
@order_groups.map { |g| OrderGroupWrapper.new(g) }
end
def result_group
OrderGroupWrapper.new(@result_group)
end
def decoder_name
"#{@stage}_decoder"
end
def decoder_name
"#{@stage}_decoder"
end
def to_vhdl
file_content = File.read(TempletePath)
templete = ERB.new(file_content, nil, '-')
templete.result(binding)
end
end
class OrderGroup
def self.new_each_stage(signals, signal_types, order_state_maps, order_type)
order_state_maps =
order_state_maps
.values
.transpose.map { |v| Hash[order_state_maps.keys.zip(v)] }
[signals, signal_types, order_state_maps].transpose.map do |args|
new(*args, order_type)
end
end
attr_reader :signal, :signal_type, :order_state_map, :order_type
def initialize(signal, signal_type, order_state_map, order_type)
@signal = signal
@order_state_map = order_state_map
@signal_type = signal_type
@order_type = order_type
end
end
class OrderGroupWrapper
extend Forwardable
def_delegators :@order_group,
:signal, :signal_type, :order_type, :order_state_map
def initialize(order_group)
@order_group = order_group
end
def input_name
order_type.gsub(/_type$/, '')
end
def group_by_select
(tb = order_state_map.except_keys_in('others'))
.keys
.group_by { |k| tb[k] }
end
def others_value
order_state_map['others']
end
end
DecoderMaker.new(ARGV[0], ARGV[1]).run
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.const_opcode.all;
use work.typedef_opcode.all;
use work.const_pipeline_state.all;
entity exec_state_decoder is
port(
opcode: in opcode_type;
funct: in funct_type;
state: out exec_state_type
);
end exec_state_decoder;
architecture behave of exec_state_decoder is
signal exec_state_io: exec_state_type;
signal exec_state_f_group: exec_state_type;
signal exec_state_r_group: exec_state_type;
signal exec_state_result: exec_state_type;
begin
with funct select
exec_state_io <=
exec_state_nop when io_fun_oh | io_fun_ob | io_fun_ow | io_fun_ih | io_fun_ib | io_fun_iw,
exec_state_nop when others;
with funct select
exec_state_f_group <=
exec_state_fpu when f_fun_fsqrt | f_fun_finv | f_fun_fmul | f_fun_fadd,
exec_state_sub_fpu when others;
with funct select
exec_state_r_group <=
exec_state_jmpr when r_fun_jalr | r_fun_jr,
exec_state_alu_shift when r_fun_sra | r_fun_srl | r_fun_sll,
exec_state_alu when others;
with opcode select
exec_state_result <=
exec_state_jmp when i_op_jal | i_op_j,
exec_state_alu_imm when i_op_slti | i_op_addi,
exec_state_sub_fpu when i_op_fmvi,
exec_state_alu when i_op_imvf | i_op_bgez | i_op_bgtz | i_op_blez | i_op_bltz | i_op_bne | i_op_beq,
exec_state_nop when i_op_lwf | i_op_lw | i_op_swf | i_op_sw,
exec_state_io when i_op_io,
exec_state_f_group when i_op_f_group,
exec_state_r_group when i_op_r_group,
exec_state_alu_zimm when others;
state <= exec_state_result;
end behave;
dependencies:
- const_opcode
- typedef_opcode
- const_pipeline_state
pipeline_stage:
- fetch
- decode
- execute
- memory
- write_back
has_state:
- exec
- mem
- write_back
order:
settings:
type:
opcode
prefix:
i_op
beq:
bne:
bltz:
blez:
bgtz:
bgez:
- alu
- branch
- nop
sw:
- nop
- sram_write
- nop
# TODO implement mem_fpu_write
swf:
- nop
- sram_write
- nop
lw:
- nop
- sram_read
- mem_wb
# TODO implement mem_fpu_wb
lwf:
- nop
- sram_read
- mem_wb
# TODO move r_group
imvf:
- alu
- nop
- fpu_wb
fmvi:
- sub_fpu
- nop
- alu_wb
addi:
slti:
- alu_imm
- nop
- alu_imm_wb
j:
- jmp
- nop
- nop
jal:
- jmp
- nop
- jal_wb
others:
- alu_zimm
- nop
- alu_imm_wb
r_group:
settings:
type:
funct
prefix:
r_fun
sll:
srl:
sra:
- alu_shift
- nop
- alu_wb
jr:
- jmpr
- nop
- nop
jalr:
- jmpr
- nop
- jal_wb
others:
- alu
- nop
- alu_wb
f_group:
settings:
type:
funct
prefix:
f_fun
fadd:
fmul:
finv:
fsqrt:
- fpu
- nop
- fpu_wb
others:
- sub_fpu
- nop
- fpu_wb
io:
settings:
type:
funct
prefix:
io_fun
iw:
- nop
- io_write_w
- io_wb
ib:
- nop
- io_write_b
- io_wb
ih:
- nop
- io_write_h
- io_wb
ow:
- nop
- io_read_w
- nop
ob:
- nop
- io_read_b
- nop
oh:
- nop
- io_read_h
- nop
others:
- nop
- nop
- nop
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
<%- dependencies.each do |dep| -%>
use work.<%= dep %>.all;
<%- end -%>
entity <%= decoder_name %> is
port(
opcode: in opcode_type;
funct: in funct_type;
state: out <%= result_group.signal_type %>
);
end <%= decoder_name %>;
architecture behave of <%= decoder_name %> is
<%- groups.each do |group| -%>
signal <%= group.signal %>: <%= group.signal_type %>;
<%- end -%>
begin
<%- groups.each do |group| %>
with <%= group.input_name %> select
<%= group.signal %> <=
<%- group.group_by_select.each do |state, orders| -%>
<%= state %> when <%= orders.join(' | ') %>,
<%- end -%>
<%= group.others_value %> when others;
<%- end %>
state <= <%= result_group.signal %>;
end behave;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment