#!/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 . # # 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 TCL-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