Files
vhdl/lib/CPUs/JCpu/tools/jasm.rb
T
jens 2361b4a440 - m�nor changes
Committed on the Free edition of March Hare Software CVSNT Server.
Upgrade to CVS Suite for more features and support:
http://march-hare.com/cvsnt/


git-svn-id: http://moon:8086/svn/vhdl/trunk@947 cc03376c-175c-47c8-b038-4cd826a8556b
2013-02-09 10:49:51 +00:00

815 lines
25 KiB
Ruby

#!/usr/bin/env ruby
# ----------------------------------------------------------------------
# Project: JCPU, a portable 8-bit RISC CPU written in VHDL
# This file: A small assembler for the JCPU
#
# Copyright (C) 2007 J. Ahrensfeld
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# For questions and ideas, please contact the author at jens@jayfield.org
#
# ---------------------------------------------------------------------
arg = $*
FILE_SUFFIX = "jsm"
IROM_MAX_SIZE = 1024
IROM_ENTITY_NAME = "irom"
IROM_DATA_TYPE = "inst_t"
IROM_ADDR_TYPE = "inst_addr_t"
XROM_MAX_SIZE = 256
XROM_DATA_TYPE = "dmem_data_t"
XROM_ADDR_TYPE = "dmem_addr_t"
XROM_ENTITY_NAME = "xrom"
OPC_LIST_NAME = "/cygdrive/w/vhdl/lib/CPUs/JCpu/tools/opc.list"
# --------------------------------------------------------
class Parser
def curr_segment
@curr_segment
end
def curr_segment=(arg)
@curr_segment=arg
end
def add_label(labelname, addr)
@label_list = @label_list + [labelname, addr]
end
def getLabelIdByName(label)
return @label_list.rindex(label)
end
def getLabelNameById(id)
return @label_list[id]
end
def put_instr(name, lc, opc , op1 , op2)
if get_instr != nil
STDERR.puts format("Error in line %d: Overlapping sections at %3.3X", lc, @pc)
exit 1
end
@instr_list[@pc] = [lc, @pc, opc , op1 , op2, name]
end
def get_instr
return @instr_list[@pc]
end
def put_xmem(value, lc)
if get_xmem != nil
STDERR.puts format("Error in line %d: Overlapping sections at %3.3X (%s)", lc, xmem_dc, curr_segment)
exit 1
end
@xmem[xmem_dc] = value
@xmem_dc = xmem_dc + 1
end
def get_xmem
return @xmem[xmem_dc]
end
def xmem
return @xmem
end
def put_cmem(value, lc)
if get_cmem(page) != nil
STDERR.puts format("Error in line %d: Overlapping sections at %3.3X (%s)", lc, cmem_dc, curr_segment)
exit 1
end
@cmem[page][cmem_dc] = value
@cmem_dc[page] = cmem_dc + 1
end
def get_cmem(pg)
return @cmem[pg][cmem_dc]
end
def cmem(page)
return @cmem[page]
end
def cmem_dc=(addr)
@cmem_dc[page] = addr
end
def cmem_dc
@cmem_dc[page]
end
def xmem_dc=(addr)
@xmem_dc = addr
end
def xmem_dc
@xmem_dc
end
def page=(page)
@page = page;
end
def page
@page;
end
def pc=(pc)
@pc = pc;
if (pc > @pc_max)
@pc_max = pc
end
end
def pc
@pc;
end
def pc_max
@pc_max;
end
def instr_list
@instr_list
end
def label_list
@label_list
end
def initialize()
@pc_max = 0
@pc = 0 # Program counter
@cmem_dc = [0,0,0,0] # chip data counter
@xmem_dc = 0 # xmem data counter
@curr_segment = "UNDEF";
@page = 0
@label_list=[[],[]]
@instr_list=[nil]
@cmem = [[],[]];
@xmem = [];
end
def method_missing(name, *args)
puts "I don't know the method #{name}"
end
end
# --------------------------------------------------------
def parse(name, obj)
lc = 0 # Line counter
file = File.open(name, "r")
file.each do |raw_line|
lc += 1
# Make all upper case
iline = "#{raw_line}".strip
# Remove comments
iline = iline.gsub(/;.*/, "")
# Split instruction at spaces
iline_member = iline.split(" ")
if iline_member[0] == nil
next
end
mc = 0;
label = nil
clean_line = nil
if (iline_member[0] =~ /\w+:/)
mc += 1
label = iline_member[0].delete(":")
if obj.getLabelIdByName(label) != nil
STDERR.puts format("Error in line %d: Duplicate label \"%s\" found", lc, label)
exit 1
end
end
token = iline_member[mc]
if token
token = token.upcase
end
case token
when nil
if obj.curr_segment == "CMEM"
curr_addr = format("0x%3.3X",obj.cmem_dc)
elsif obj.curr_segment == "XMEM"
curr_addr = format("0x%3.3X",obj.xmem_dc)
elsif obj.curr_segment == "CODE"
curr_addr = format("0x%3.3X",obj.pc)
else
STDERR.puts format("Error in line %d: Undefined segment", lc)
exit 1
end
when "INCLUDE"
if iline_member[mc+1] == nil
STDERR.puts format("Error in line %d: %s needs argument!", lc, token)
exit 1
end
inc_name = iline_member[mc+1].delete("\"")
puts format("Inserting \"%s\" into \"%s\" at line %d", inc_name, name, lc);
parse(inc_name, obj)
when "EQU"
if iline_member[mc+1] == nil
STDERR.puts format("Error in line %d: %s needs argument!", lc, token)
exit 1
end
if 0 == (iline_member[mc+1] =~ /\d+/)
curr_addr = format("0x%2.2X",eval(iline_member[mc+1..iline_member.nitems].to_s))
else
curr_addr = iline_member[mc+1]
end
when "ORG"
if iline_member[mc+1] == nil
STDERR.puts format("Error in line %d: %s needs argument!", lc, token)
exit 1
end
offset = eval(iline_member[mc+1..iline_member.nitems].to_s)
case obj.curr_segment
when "CODE"
obj.pc = offset
curr_addr = format("0x%3.3X",obj.pc)
when "CMEM"
obj.cmem_dc = offset
when "XMEM"
obj.xmem_dc = offset
end
when "CODE"
curr_addr = format("0x%3.3X",obj.pc)
obj.curr_segment = "CODE";
when "CDATA", "CMEM"
if iline_member[mc+1] == nil
STDERR.puts format("Error in line %d: %s needs argument!", lc, token)
exit 1
end
obj.curr_segment = "CMEM";
obj.page = iline_member[mc+1].to_i(16)
when "XDATA", "XMEM"
obj.curr_segment = "XMEM";
when "DC"
len = 0;
if iline_member[mc+1] == nil
STDERR.puts format("Error in line %d: %s needs argument!", lc, token)
exit 1
end
if obj.curr_segment == "CMEM"
STDERR.puts format("Error in line %d: %s cannot be initialized!", lc, obj.curr_segment)
exit 1
elsif obj.curr_segment == "XMEM"
curr_addr = format("0x%2.2X",obj.xmem_dc)
dc_old = obj.xmem_dc;
val_array = raw_line.split(/dc|DC|Dc|dC/)[1].delete("\t").gsub(/;.*/, "").split(",")
# Parse string literals
val_array.each do |item|
if 0 == (item =~ /.*\".*\"/)
str = item.delete("\"")
puts item
for nn in (0..str.length-1)
if str[nn] > 31
obj.put_xmem(str[nn], lc);
puts "S: " + str[nn].to_s
len += 1
end
end;
else
argument = item
puts "B: " + argument
obj.put_xmem(eval(argument), lc);
len += 1
end
end
puts format("Found DC defining %d bytes at 0x%4.4X in %s", len, dc_old, obj.curr_segment);
else
STDERR.puts format("Error in line %d: Invalid segment %s for \"%s\"", lc, obj.curr_segment, token)
exit 1
end
when "DB"
if iline_member[mc+1] == nil
STDERR.puts format("Error in line %d: %s needs argument!", lc, token)
exit 1
end
len = eval(iline_member[mc+1]).to_i
if obj.curr_segment == "CMEM"
curr_addr = format("0x%2.2X",obj.cmem_dc)
puts format("Found DB reserving %d bytes at 0x%4.4X in %s(%d)", len, obj.cmem_dc, obj.curr_segment, obj.page);
for nn in (1..len)
obj.put_cmem(0, lc)
end
elsif obj.curr_segment == "XMEM"
curr_addr = format("0x%2.2X",obj.xmem_dc)
puts format("Found DB reserving %d bytes at 0x%4.4X in %s", len, obj.xmem_dc, obj.curr_segment);
for nn in (1..len)
obj.put_xmem(0, lc)
end
else
STDERR.puts format("Error in line %d: Invalid segment %s for \"%s\"", lc, obj.curr_segment, token)
exit 1
end
else
if obj.curr_segment != "CODE"
STDERR.puts format("Error in line %d: Invalid segment %s for \"%s\"", lc, obj.curr_segment, token)
exit 1
end
op_line = iline_member[mc+1..iline_member.nitems].to_s
curr_addr = format("0x%3.3X",obj.pc)
opc = token
if iline_member[mc+1] != nil
op1 = op_line.gsub(/,+.*$/, "")
end
if iline_member[mc+2] != nil
op2 = op_line.scan(/,.+$/).to_s.delete(", ")
end
obj.put_instr(name, lc, opc, op1, op2)
obj.pc = obj.pc + 1
end;
# Push labels
if label
obj.add_label(label, curr_addr)
end
end
file.close
return obj
end
# --------------------------------------------------------
# Instruction formatting
# --------------------------------------------------------
def instr(opcode)
return format("\"%6.6B\" & X\"%3.3X\"",opcode ,0)
end
def tcl_bits(pc, opcode)
return format("%12.12B%8.8B%12.12B",pc, opcode ,0)
end
def instr_k(opcode, k)
return format("\"%6.6B\" & X\"%3.3X\"",opcode ,k)
end
def tcl_bits_k(pc, opcode, k)
return format("%12.12B%8.8B%12.12B",pc, opcode ,k)
end
def instr_r(opcode, r)
return format("\"%6.6B\" & X\"%2.2X%X\"",opcode ,0, r)
end
def tcl_bits_r(pc, opcode, r)
return format("%12.12B%8.8B%8.8B%4.4B",pc, opcode ,0,r)
end
def instr_kr(opcode, k, r)
return format("\"%6.6B\" & X\"%2.2X%X\"",opcode,k, r)
end
def tcl_bits_kr(pc, opcode, k, r)
return format("%12.12B%8.8B%8.8B%4.4B",pc, opcode, k, r)
end
def instr_rk(opcode, r, k)
return format("\"%6.6B\" & X\"%2.2X%X\"",opcode,k, r)
end
def tcl_bits_rk(pc, opcode, r, k)
return format("%12.12B%8.8B%8.8B%4.4B",pc, opcode, k, r)
end
def instr_rr(opcode, ra, rb)
return format("\"%6.6B\" & X\"%X%X%X\"",opcode,0, rb, ra)
end
def tcl_bits_rr(pc, opcode, ra, rb)
return format("%12.12B%8.8B%4.4B%4.4B%4.4B",pc, opcode, 0, rb, ra)
end
# --------------------------------------------------------
# Open file
# --------------------------------------------------------
filename = arg.to_s
if !File.exists?(filename)
STDERR.puts "#{filename} does not exist"
exit 1
end
PROJECT_NAME = File.basename(filename, "." + FILE_SUFFIX)
# --------------------------------------------------------
# Pass 1
# --------------------------------------------------------
first_pass = Parser.new();
parse(filename, first_pass)
# --------------------------------------------------------
# Read mnemonic set
# --------------------------------------------------------
filename = OPC_LIST_NAME
if !File.exists?(filename)
STDERR.puts "#{filename} does not exist"
exit 1
end
mnemo_list = []
num_opcodes = 0
file = File.open(filename, "r")
file.each do |raw_line|
mnemo_list[num_opcodes] = raw_line.split(" ")[1]
num_opcodes += 1
end
# --------------------------------------------------------
# Pass 2
# --------------------------------------------------------
pc = 0
opc_start = 2
num_errors = 0
vhdl_trans_list = [nil]
vhdl_comment_list = [nil]
vhdl_tcl_list = [nil]
# ToDo: Use class-methods
label_list = first_pass.label_list
instr_list = first_pass.instr_list
instr_list.each do |instruct|
# puts instruct
if instruct == nil
vhdl_trans_list[pc] = format("\"%6.6B\" & X\"%3.3X\"",0 ,0)
vhdl_comment_list[pc] = format("0x%3.3X:", pc)
vhdl_tcl_list[pc] = tcl_bits(pc, 0)
pc += 1
next
end
# determine arglen of instruction
ilen = 0
if instruct[opc_start+1] == nil
arglen = 0
elsif instruct[opc_start+2] == nil
arglen = 1
elsif instruct[opc_start+3] == nil
arglen = 2
end
# Symbol substitution
error = false
for i in (1..2)
subst_pos = opc_start+i
if instruct[subst_pos] == nil
next
end
expr_token = ""
expr_subst = nil
is_direct = true;
# checks R0 .. R16, Mnemonics
instruct[subst_pos] = instruct[subst_pos].gsub(/'low/, "")
if (nil != (instruct[subst_pos] =~ /'high/))
instruct[subst_pos]= format("%s/256", instruct[subst_pos].gsub(/'high/, ""))
end
instr_str = instruct[subst_pos]
if 0 == (instr_str =~ /\(.+\)/)
instr_str = instr_str.delete("()")
is_direct = false;
end
expr_token = instr_str.split(/\+|\-|\*|\/|\||\&/)[0]
if (0 != (expr_token =~ /R[0-9]+/)) && (0 != (expr_token =~ /\d+/))
idx = label_list.rindex(expr_token)
if idx != nil
expr_subst = label_list[idx+1]
instruct[subst_pos] = instruct[subst_pos].gsub(expr_token, expr_subst)
else
STDERR.puts format("%s: Error in line %d: Symbol \"%s\" not found", instruct[5], instruct[0], expr_token)
error = true
end
end
if expr_subst != nil
if 0 == (expr_subst =~ /\d+/)
if is_direct == true
instruct[subst_pos] = format("0x%2.2X", eval(instruct[subst_pos]))
else
instruct[subst_pos] = format("(0x%2.2X)", eval(instruct[subst_pos]))
end
else
if 0 != (expr_subst =~ /R[0-9]+/)
STDERR.puts format("%s: Error in line %d: Invalid expression \"%s\"", instruct[5], instruct[0], expr_subst)
error = true
end
end
end
end
# Parse operands
reg = [0,0]
kk = 0
format = instruct[opc_start]
for i in (0..1)
if instruct[opc_start+i+1] =~ Regexp.new("R[0-9]+")
# Check indirect addressing
reg[i] = instruct[opc_start+i+1].delete("R()").to_i
format += "|R"
if reg[i] > 15
STDERR.puts format("%s: Error in line %d: Invalid register \"R%d\" specified", instruct[5], instruct[0], reg[i])
error = true
end
else
if instruct[opc_start+i+1] =~ Regexp.new("[0-9A-F]+")
kk = eval(instruct[opc_start+i+1].delete("()"))
format += "|K"
end
end
if instruct[opc_start+i+1] =~ Regexp.new("\\(.+\\)")
format += "i";
end
end
if error
num_errors += 1
break
end
# Output instruction
opcode = mnemo_list.rindex(format).to_i
mnemo = instruct[2];
case format
# Native instructions
when "NOP", "HALT", "RET", "RETI", "SETC"
vhdl_trans_list[pc] = instr(opcode)
vhdl_tcl_list[pc] = tcl_bits(pc, opcode)
minstr_comment = format("0x%3.3X: %s", pc, mnemo)
when "MOVC|R|Ri", "MOVX|R|Ri"
vhdl_trans_list[pc] = instr_rr(opcode, reg[0], reg[1]);
vhdl_tcl_list[pc] = tcl_bits_rr(pc, opcode, reg[0], reg[1])
minstr_comment = format("0x%3.3X: %s R%2.2d, (R%2.2d)", pc, mnemo, reg[0], reg[1])
when "MOV|R|R", "SUB|R|R", "SUBC|R|R", "ADD|R|R", "ADDC|R|R", "AND|R|R", "OR|R|R", "XOR|R|R", "CMP|R|R"
vhdl_trans_list[pc] = instr_rr(opcode, reg[0], reg[1]);
vhdl_tcl_list[pc] = tcl_bits_rr(pc, opcode, reg[0], reg[1])
minstr_comment = format("0x%3.3X: %s R%2.2d, R%2.2d", pc, mnemo, reg[0], reg[1])
when "MOVC|Ri|R", "MOVX|Ri|R"
vhdl_trans_list[pc] = instr_rr(opcode, reg[1], reg[0]);
vhdl_tcl_list[pc] = tcl_bits_rr(pc, opcode, reg[1], reg[0])
minstr_comment = format("0x%3.3X: %s (R%2.2d), R%2.2d", pc, mnemo, reg[1], reg[0])
when "MOVC|Ri|K", "MOVX|Ri|K", "COUT|Ri|K", "XOUT|Ri|K"
kk = kk % 256;
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
minstr_comment = format("0x%3.3X: %s (R%2.2d), 0x%2.2X", pc, mnemo, reg[0], kk)
when "MOVC|R|Ki", "MOVX|R|Ki", "CIN|R|Ki", "XIN|R|Ki"
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
minstr_comment = format("0x%3.3X: %s R%2.2d, (0x%2.2X)", pc, mnemo, reg[0], kk)
when "MOV|R|K", "SUB|R|K", "SUBC|R|K", "ADD|R|K", "ADDC|R|K", "AND|R|K", "OR|R|K", "XOR|R|K", "CMP|R|K"
kk = kk % 256;
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
minstr_comment = format("0x%3.3X: %s R%2.2d, 0x%2.2X", pc, mnemo, reg[0], kk)
when "SUB|K|R", "SUBC|K|R"
kk = kk % 256;
vhdl_trans_list[pc] = instr_kr(opcode, kk, reg[1]);
vhdl_tcl_list[pc] = tcl_bits_kr(pc, opcode, kk, reg[1])
minstr_comment = format("0x%3.3X: %s 0x%2.2d, R%2.2X", pc, mnemo, kk, reg[1])
when "MOVC|Ki|R", "MOVC|Ki|R", "MOVX|Ki|R", "MOVX|Ki|R", "COUT|Ki|R", "XOUT|Ki|R"
vhdl_trans_list[pc] = instr_kr(opcode, kk, reg[1]);
vhdl_tcl_list[pc] = tcl_bits_kr(pc, opcode, kk, reg[1])
minstr_comment = format("0x%3.3X: %s (0x%2.2X), R%2.2d", pc, mnemo, kk, reg[1])
when "CALL|K", "JMP|K", "JNZ|K", "JZ|K","JNC|K", "JC|K", "JLT|K", "JGT|K", "JLE|K", "JGE|K", "JEQ|K", "JNE|K"
vhdl_trans_list[pc] = instr_k(opcode, kk)
vhdl_tcl_list[pc] = tcl_bits_k(pc, opcode, kk)
minstr_comment = format("0x%3.3X: %s 0x%3.3X", pc, mnemo, kk)
when "PUSH|R", "POP|R", "SHR|R", "SHL|R", "ROR|R", "ROL|R", "RORC|R", "ROLC|R", "SWAP|R"
vhdl_trans_list[pc] = instr_r(opcode, reg[0])
vhdl_tcl_list[pc] = tcl_bits_r(pc, opcode, reg[0])
minstr_comment = format("0x%3.3X: %s R%2.2d", pc, mnemo, reg[0])
# Synthetic instructions
when "CLRC"
kk = 0;
minstr_comment = format("0x%3.3X: %s", pc, mnemo)
opcode = mnemo_list.rindex("SUB|R|K").to_i
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
when "TST|R"
kk = 0
minstr_comment = format("0x%3.3X: %s R%2.2d", pc, mnemo, reg[0])
opcode = mnemo_list.rindex("CMP|R|K").to_i
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
when "NEG|R"
kk = 0
minstr_comment = format("0x%3.3X: %s R%2.2d", pc, mnemo, reg[0])
opcode = mnemo_list.rindex("SUB|K|R").to_i
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
when "NOT|R"
kk = 0
minstr_comment = format("0x%3.3X: %s R%2.2d", pc, mnemo, reg[0])
opcode = mnemo_list.rindex("XOR|R|K").to_i
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
when "INC|R"
kk = 1
minstr_comment = format("0x%3.3X: %s R%2.2d", pc, mnemo, reg[0])
opcode = mnemo_list.rindex("ADD|R|K").to_i
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
when "DEC|R"
kk = 1
minstr_comment = format("0x%3.3X: %s R%2.2d", pc, mnemo, reg[0])
opcode = mnemo_list.rindex("SUB|R|K").to_i
vhdl_trans_list[pc] = instr_rk(opcode, reg[0], kk);
vhdl_tcl_list[pc] = tcl_bits_rk(pc, opcode, reg[0], kk)
else
STDERR.puts format("%s: Error in line %d: Not yet implemented %s", instruct[5], instruct[0], format)
error = true
end
if error
num_errors += 1
break
end
vhdl_comment_list[pc] = minstr_comment
puts vhdl_trans_list[pc] + " -- " + minstr_comment
pc += 1
end
# --------------------------------------------------------
# Output ROM file
# --------------------------------------------------------
if num_errors == 0
# I-ROM VHDL-ROM
filename = format("%s.irom.vhdl.snip", PROJECT_NAME)
file = File.open(filename, "w")
file.puts format("ENTITY %s IS\n", IROM_ENTITY_NAME)
file.puts format("\tPort (\n")
file.puts format("\tclk\t\t\t: in STD_LOGIC;\n")
file.puts format("\tce\t\t\t: in STD_LOGIC;\n")
file.puts format("\taddr\t\t: in %s;\n", IROM_ADDR_TYPE)
file.puts format("\tdout\t\t: out %s\n", IROM_DATA_TYPE)
file.puts format("\t);\n")
file.puts format("END %s;\n", IROM_ENTITY_NAME)
file.puts format("\n")
file.puts format("ARCHITECTURE %s OF %s IS \n", PROJECT_NAME, IROM_ENTITY_NAME)
file.puts format("\n")
file.puts format("\ttype imem_rom_t is array (0 to %d) of %s;\n", [IROM_MAX_SIZE, pc].min-1 , IROM_DATA_TYPE)
file.puts format("\n")
file.puts format("\t-- Assembled from %s.%s", PROJECT_NAME, FILE_SUFFIX)
file.puts format("\tconstant imem_rom : imem_rom_t :=\n")
file.puts format("\t(\n");
for i in (0..[IROM_MAX_SIZE, pc].min-2)
file.puts "\t\t" + vhdl_trans_list[i] + ", -- " + vhdl_comment_list[i] + "\n"
end;
file.puts "\t\t" + vhdl_trans_list[pc-1] + " -- " + vhdl_comment_list[pc-1] + "\n"
file.puts format("\t);\n")
file.puts format("\n")
file.puts format("begin")
file.puts format("\n")
file.puts format("PROM_READ:")
file.puts format("\tprocess(clk, ce)\n")
file.puts format("\tbegin\n")
file.puts format("\t\tif rising_edge(clk) and ce = '1' then\n")
file.puts format("\t\t\tdout <= imem_rom(to_integer(addr));\n")
file.puts format("\t\tend if;\n")
file.puts format("\tend process;\n")
file.puts format("\n")
file.puts format("end %s;\n", PROJECT_NAME)
puts format("I-ROM file written to \"%s\"\n",filename)
file.close
# I-ROM VHDL-ROM (loadable)
filename = format("%s.irom_ld.vhdl.snip", PROJECT_NAME)
file = File.open(filename, "w")
file.puts format("\n\t-- Assembled from %s.%s", PROJECT_NAME, FILE_SUFFIX)
file.puts format("\ttype imem_rom_t is array (0 to %d) of %s;\n", IROM_MAX_SIZE-1, IROM_DATA_TYPE)
file.puts format("\tsignal imem_rom : imem_rom_t :=\n")
file.puts format("\t(\n");
for i in (0..pc-2)
file.puts "\t\t" + vhdl_trans_list[i] + ", -- " + vhdl_comment_list[i] + "\n"
end;
if pc < (IROM_MAX_SIZE-1)
file.puts "\t\t" + vhdl_trans_list[pc-1] + ", -- " + vhdl_comment_list[pc-1] + "\n"
for i in (pc..(IROM_MAX_SIZE-2))
file.puts "\t\t" + instr(0) + ",\n"
end;
file.puts "\t\t" + instr(0) + "\n"
else
file.puts "\t\t" + vhdl_trans_list[pc-1] + " -- " + vhdl_comment_list[pc-1] + "\n"
end
file.puts format("\t);\n")
puts format("I-ROM (loadable) file written to \"%s\"\n",filename)
file.close
# I-ROM TCL-Loader
filename = format("%s.irom.tcl.snip", PROJECT_NAME)
file = File.open(filename, "w")
file.puts format("# Assembled from %s.%s", PROJECT_NAME, FILE_SUFFIX)
file.puts format("# ---------------------------------------------------------------");
file.puts format("# Shift the USER1 Instruction (b1111000010) into the Instruction Register of FPGA");
file.puts format("# User 1")
file.puts format("set result [::chipscope::csejtag_tap shift_device_ir $handle $devid $CSE_OP $CSE_ES 0 $irlength \"3C2\"]\n\n")
for i in (0..pc-1)
# Chipscope 8.1
# file.puts format("jtag_shiftdr $handle -buffer \"%s\" -endstate RTI -device $devid", vhdl_tcl_list[i].reverse);
# Chipscope 9.1
file.puts format("\# %s", vhdl_comment_list[i])
file.puts format("::chipscope::csejtag_tap shift_device_dr $handle $devid $CSE_OP $CSE_ES 0 %d \"%8.8X\"\n\n", vhdl_tcl_list[i].length, vhdl_tcl_list[i].to_i(2));
end;
puts format("I-ROM TCL-loader written to \"%s\"\n",filename)
file.close
# X-ROM VHDL-ROM
filename = format("%s.xrom.vhdl.snip", PROJECT_NAME)
file = File.open(filename, "w")
file.puts format("ENTITY %s IS\n", XROM_ENTITY_NAME)
file.puts format("\tPort (\n")
file.puts format("\tclk\t\t\t: in STD_LOGIC;\n")
file.puts format("\tce\t\t\t: in STD_LOGIC;\n")
file.puts format("\taddr\t\t: in %s;\n", XROM_ADDR_TYPE)
file.puts format("\tdout\t\t: out %s\n", XROM_DATA_TYPE)
file.puts format("\t);\n")
file.puts format("END %s;\n", XROM_ENTITY_NAME)
file.puts format("\n")
file.puts format("ARCHITECTURE %s OF %s IS \n", PROJECT_NAME, XROM_ENTITY_NAME)
file.puts format("\n")
file.puts format("\ttype xmem_rom_t is array (0 to %d) of %s;\n", XROM_MAX_SIZE-1, XROM_DATA_TYPE)
file.puts format("\n")
file.puts format("\t-- Assembled from %s.%s", PROJECT_NAME, FILE_SUFFIX)
file.puts format("\tconstant xmem_rom : xmem_rom_t :=\n")
file.puts format("\t(\n");
for i in (0..XROM_MAX_SIZE-2)
file.puts format("\t\tX\"%2.2X\", -- 0x%2.2X\n", first_pass.xmem[i], i)
end;
i = XROM_MAX_SIZE-1
file.puts format("\t\tX\"%2.2X\" -- 0x%2.2X\n", first_pass.xmem[i], i)
file.puts format("\t);\n")
file.puts format("\n")
file.puts format("begin")
file.puts format("\n")
file.puts format("PROM_READ:")
file.puts format("\tprocess(clk, ce)\n")
file.puts format("\tbegin\n")
file.puts format("\t\tif rising_edge(clk) and ce = '1' then\n")
file.puts format("\t\t\tdout <= xmem_rom(to_integer(addr));\n")
file.puts format("\t\tend if;\n")
file.puts format("\tend process;\n")
file.puts format("\n")
file.puts format("end %s;\n", PROJECT_NAME)
puts format("X-ROM file written to \"%s\"\n",filename)
file.close
# X-ROM VHDL-ROM (loadable)
filename = format("%s.xrom_ld.vhdl.snip", PROJECT_NAME)
file = File.open(filename, "w")
file.puts format("\n\t-- Assembled from %s.%s", PROJECT_NAME, FILE_SUFFIX)
file.puts format("\ttype xmem_rom_t is array (0 to %d) of %s;\n", XROM_MAX_SIZE-1, XROM_DATA_TYPE)
file.puts format("\tsignal xmem_rom : xmem_rom_t :=\n")
file.puts format("\t(\n");
for i in (0..XROM_MAX_SIZE-2)
file.puts format("\t\tX\"%2.2X\", -- 0x%2.2X\n", first_pass.xmem[i], i)
end;
i = XROM_MAX_SIZE-1
file.puts format("\t\tX\"%2.2X\" -- 0x%2.2X\n", first_pass.xmem[i], i)
file.puts format("\t);\n")
puts format("X-ROM (loadable) file written to \"%s\"\n",filename)
file.close
# X-ROM JTAG-Loader
filename = format("%s.xrom.tcl.snip", PROJECT_NAME)
file = File.open(filename, "w")
file.puts format("# Assembled from %s.%s", PROJECT_NAME, FILE_SUFFIX)
file.puts format("# ---------------------------------------------------------------");
file.puts format("# Shift the USER2 Instruction (b1111000011) into the Instruction Register of FPGA");
file.puts format("# User 2")
file.puts format("set result [::chipscope::csejtag_tap shift_device_ir $handle $devid $CSE_OP $CSE_ES 0 $irlength \"3C3\"]\n\n")
for i in (0..first_pass.xmem.length-1)
# Chipscope 8.1
# file.puts format("jtag_shiftdr $handle -buffer \"%s\" -endstate RTI -device $devid", vhdl_tcl_list[i].reverse);
# Chipscope 9.1
file.puts format("::chipscope::csejtag_tap shift_device_dr $handle $devid $CSE_OP $CSE_ES 0 %d \"%2.2X%2.2X\"\n", 16, i, first_pass.xmem[i]);
end;
puts format("X-ROM TCL-loader written to \"%s\"\n",filename)
file.close
end
# --------------------------------------------------------
# Output final statistics
# --------------------------------------------------------
if num_errors == 0
puts "Program uses #{first_pass.pc_max} instruction addresses"
puts "No errors found"
exit 0
else
puts "#{num_errors} errors found"
exit 1
end