diff --git a/tools/jcpu/eval_scan.rb b/tools/jcpu/eval_scan.rb
new file mode 100755
index 0000000..0c38397
--- /dev/null
+++ b/tools/jcpu/eval_scan.rb
@@ -0,0 +1,42 @@
+#!/usr/bin/env ruby
+
+str1 = %Q!lbl: dc "Hallo", ", ", 0, 1, " der","Jens"!
+
+i=0;
+
+def get_stri_lit (str)
+ res = [""];
+ state = "out"
+
+ j = 0;
+ k = 0;
+ for i in (0..str.length-1)
+ c = str[i];
+ nstate = state
+ case state
+ when "out"
+ if c == "\""[0]
+ nstate = "in"
+ end
+ when "in"
+ if c == "\""[0]
+ nstate = "out"
+ if j > 0
+ k = k + 1;
+ res[k] = ""
+ end
+ else
+ res[k] = res[k] + format("%c", c);
+ j = j + 1;
+ end
+ end
+ state = nstate
+ end;
+ return res
+end
+
+get_stri_lit(str1).each do |word|
+ puts word
+end
+
+
\ No newline at end of file
diff --git a/tools/jcpu/insrom.rb b/tools/jcpu/insrom.rb
new file mode 100755
index 0000000..6713f9f
--- /dev/null
+++ b/tools/jcpu/insrom.rb
@@ -0,0 +1,46 @@
+#!/usr/bin/env ruby
+
+# ----------------------------------------------------------------------
+# Project: JCPU, a portable 8-bit RISC CPU written in VHDL
+# This file: Insertion of code fragments into templates
+#
+# 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 = $*
+rom_filename = arg[0].to_s
+tpl_filename = arg[1].to_s
+
+subst_pattern = "JASM_ROM_INSERT_HERE"
+
+# --------------------------------------------------------
+# Open file
+# --------------------------------------------------------
+romfile = File.open(rom_filename, "r")
+tplfile = File.open(tpl_filename, "r")
+re = Regexp.new(subst_pattern)
+
+while (line = tplfile.gets)
+ puts line
+ line.scan(re).each do |word|
+ romfile.each do |raw_line|
+ puts raw_line
+ end
+ end
+end
diff --git a/tools/jcpu/irom.vhd.tpl b/tools/jcpu/irom.vhd.tpl
new file mode 100644
index 0000000..5f11f86
--- /dev/null
+++ b/tools/jcpu/irom.vhd.tpl
@@ -0,0 +1,32 @@
+-------------------------------------------------------------------------
+-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
+-- This file: The ROM file for use in your VHDL design
+--
+-- 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
+--
+--------------------------------------------------------------------------
+
+LIBRARY ieee;
+use IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+library work;
+use work.cpu_pkg.all;
+
+-- JASM_ROM_INSERT_HERE
+
diff --git a/tools/jcpu/irom_ld.vhd.tpl b/tools/jcpu/irom_ld.vhd.tpl
new file mode 100644
index 0000000..eaa41f3
--- /dev/null
+++ b/tools/jcpu/irom_ld.vhd.tpl
@@ -0,0 +1,151 @@
+-------------------------------------------------------------------------
+-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
+-- This file: loadable ROM
+--
+-- 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
+--
+--------------------------------------------------------------------------
+
+LIBRARY ieee;
+use IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+library UNISIM;
+use UNISIM.VComponents.all;
+
+library work;
+use work.cpu_pkg.all;
+
+ENTITY irom IS
+ Port (
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+ addr : in inst_addr_t;
+ dout : out inst_t
+ );
+
+END irom;
+
+ARCHITECTURE loadable OF irom IS
+
+ -- JASM_ROM_INSERT_HERE
+
+ signal jtag_ld_clk : STD_LOGIC;
+ signal jtag_ld_we : STD_LOGIC;
+ signal jtag_ld_addr : inst_addr_t;
+ signal jtag_ld_dout : inst_t;
+ signal jtag_ld_din : inst_t;
+ signal bs_rst, bs_sel, bs_shift, bs_tdi, bs_tdo : std_logic;
+ signal bs_capture, bs_clk0, bs_clk1, bs_update0, bs_update1 : std_logic;
+ signal user_regi, user_rego : unsigned (31 downto 0);
+ constant id : unsigned (31 downto 0) := X"BABE" & X"BEEF";
+
+begin
+
+--------------------------------------------------------------------------
+-- Virtex-4: JTAG Loader
+--------------------------------------------------------------------------
+ i00_BUFG : BUFG
+ port map
+ (
+ O => bs_clk1,
+ I => bs_clk0
+ );
+
+ i01_BUFG : BUFG
+ port map
+ (
+ O => bs_update1,
+ I => bs_update0
+ );
+
+ BSCAN_VIRTEX4_inst1 : BSCAN_VIRTEX4
+ generic map
+ (
+ JTAG_CHAIN => 1 -- Value to set BSCAN site of device. Possible values: (1,2,3 or 4)
+ )
+ port map
+ (
+ CAPTURE => bs_capture, -- CAPTURE output from TAP controller
+ DRCK => bs_clk0, -- Data register output for USER functions
+ RESET => bs_rst, -- Reset output from TAP controller
+ SEL => bs_sel, -- USER active output
+ SHIFT => bs_shift, -- SHIFT output from TAP controller
+ TDI => bs_tdi, -- TDI output from TAP controller
+ UPDATE => bs_update0, -- UPDATE output from TAP controller
+ TDO => bs_tdo -- Data input for USER function
+ );
+
+ jtag_ld_addr <= user_regi(user_regi'left downto user_regi'left-inst_addr_t'length+1);
+ jtag_ld_din <= user_regi(inst_t'length-1 downto 0);
+ jtag_ld_clk <= bs_update1;
+ jtag_ld_we <= bs_sel;
+
+sipo:
+ process (bs_rst, bs_clk1, bs_tdi, bs_shift)
+ begin
+ if bs_rst = '1' then
+ user_regi <= (others => '0');
+ elsif rising_edge(bs_clk1) then
+ if bs_shift = '1' then
+ user_regi <= bs_tdi & user_regi(user_regi'left downto 1);
+ end if;
+ end if;
+ end process;
+
+piso:
+ process (bs_rst, bs_clk1, bs_shift, user_rego)
+ begin
+ bs_tdo <= user_rego(0);
+ if bs_rst = '1' then
+ user_rego <= (others => '0');
+ elsif rising_edge(bs_clk1) then
+ if bs_shift = '1' then
+ user_rego <= user_rego(0) & user_rego(user_rego'left downto 1);
+ else
+ user_rego <= (user_rego'left downto inst_t'length => '0') & jtag_ld_dout;
+-- user_rego <= id;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+-- ROM Read/Write
+--------------------------------------------------------------------------
+PROM_READ:
+ process(clk, ce)
+ begin
+ if rising_edge(clk) and ce = '1' then
+ dout <= imem_rom(to_integer(addr));
+ end if;
+ end process;
+
+PROM_WRITE:
+ process(jtag_ld_clk, jtag_ld_we)
+ begin
+ if rising_edge(jtag_ld_clk) then
+ if jtag_ld_we = '1' then
+ imem_rom(to_integer(jtag_ld_addr)) <= jtag_ld_din;
+ else
+ jtag_ld_dout <= imem_rom(to_integer(jtag_ld_addr));
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+end loadable;
diff --git a/tools/jcpu/jasm.bak.rb b/tools/jcpu/jasm.bak.rb
new file mode 100755
index 0000000..4c9feb0
--- /dev/null
+++ b/tools/jcpu/jasm.bak.rb
@@ -0,0 +1,494 @@
+#!/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 library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+
+# This library 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
+# Lesser General Public License for more details.
+
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# For questions and ideas, please contact the author at jens@jayfield.org
+
+# ---------------------------------------------------------------------
+
+arg = $*
+MAX_SIZE_ROM = 1024
+PROJECT_NAME = arg.to_s.gsub(/\..*/, "")
+ENTITY_NAME = "rom"
+ENTITY_DATA_TYPE = "inst_t"
+ENTITY_ADDR_TYPE = "inst_addr_t"
+OPC_LIST_NAME = "/cygdrive/w/vhdl/lib/CPUs/JCpu/tools/opc.list"
+
+# --------------------------------------------------------
+# Open file
+# --------------------------------------------------------
+filename = arg.to_s
+if !File.exists?(filename)
+ STDERR.puts "#{filename} does not exist"
+ exit 1
+end
+
+# --------------------------------------------------------
+# Pass 1
+# --------------------------------------------------------
+lc = 0 # Line counter
+pc = 0 # Program counter
+chip_dc = [0,0,0,0] # chip data counter
+xmem_dc = 0 # xmem data counter
+curr_segment = "UNDEF";
+page = 0
+
+label_list=[[],[]]
+instr_list=[nil]
+file = File.open(filename, "r")
+file.each do |raw_line|
+ lc += 1
+
+ # Make all upper case
+ iline = "#{raw_line}".strip.upcase
+
+ # 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 label_list.rindex(label) != nil
+ STDERR.puts format("Error in line %d: Duplicate label \"%s\" found", lc, label)
+ exit 1
+ end
+ end
+
+ case iline_member[mc]
+ when nil
+ value = format("0x%3.3X",pc)
+ when "EQU"
+ if 0 == (iline_member[mc+1] =~ /\d+/)
+ value = format("0x%2.2X",eval(iline_member[mc+1..iline_member.nitems].to_s))
+ else
+ value = iline_member[mc+1]
+ end
+ when "ORG", "CODE"
+ pc = eval(iline_member[mc+1..iline_member.nitems].to_s)
+ value = format("0x%3.3X",pc)
+ when "CDATA", "CMEM"
+ if iline_member[mc+1] == nil
+ STDERR.puts format("Error in line %d: CDATA needs argument!", lc)
+ exit 1
+ end
+ curr_segment = "CMEM";
+ page = iline_member[mc+1].to_i(16)
+ when "XDATA", "XMEM"
+ curr_segment = "XMEM";
+ when "DC"
+ len = 0;
+ iline.split("DC")[1].delete("0x").scan(/[0-9A-Fa-f]+/).each do |byte|
+ len += 1
+ end
+ if curr_segment == "CMEM"
+ STDERR.puts format("Error in line %d: CDATA cannot be initialized!", lc)
+ exit 1
+ else
+ value = format("0x%2.2X",xmem_dc)
+ puts format("Found DC defining %d bytes at 0x%4.4X in %s", len, xmem_dc, curr_segment);
+ xmem_dc += len
+ end
+ when "DB"
+ len = iline_member[mc+1].to_i
+ if curr_segment == "CMEM"
+ value = format("0x%2.2X",chip_dc[page])
+ puts format("Found DB reserving %d bytes at 0x%4.4X in %s(%d)", len, chip_dc[page], curr_segment, page);
+ chip_dc[page] += len
+ else
+ value = format("0x%2.2X",xmem_dc)
+ puts format("Found DB reserving %d bytes at 0x%4.4X in %s", len, xmem_dc, curr_segment);
+ xmem_dc += len
+ end
+ else
+ op_line = iline_member[mc+1..iline_member.nitems].to_s
+ value = format("0x%3.3X",pc)
+ opc = iline_member[mc]
+ 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
+ if instr_list[pc] == nil
+ instr_list[pc] = [lc, pc, opc , op1 , op2]
+ pc += 1
+ else
+ STDERR.puts format("Error in line %d: Overlapping sections at %3.3X", lc, pc)
+ exit 1
+ end
+ end;
+
+ # Push labels
+ if label
+ label_list = label_list + [label, value]
+ end
+end
+file.close
+
+# --------------------------------------------------------
+def instr(opcode)
+ return format("\"%6.6B\" & X\"%3.3X\"",opcode ,0)
+end
+
+def tcl_bits(pc, opcode)
+ return format("%10.10B%6.6B%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("%10.10B%6.6B%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("%10.10B%6.6B%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("%10.10B%6.6B%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("%10.10B%6.6B%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("%10.10B%6.6B%4.4B%4.4B%4.4B",pc, opcode, 0, rb, ra)
+end
+
+# --------------------------------------------------------
+# 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]
+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..3)
+ subst_pos = opc_start+i
+ if instruct[subst_pos] == nil
+ next
+ end
+ expr_token = ""
+ expr_subst = nil
+ is_direct = true;
+
+# instruct[subst_pos] = instruct[subst_pos].delete(" ")
+
+ # checks R0 .. R16, Mnemonics
+ 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("Error in line %d: Symbol \"%s\" not found", 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("Error in line %d: Invalid expression \"%s\"", 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("Error in line %d: Invalid register \"R%d\" specified", instruct[0], reg[i])
+ error = true
+ end
+ else
+ if instruct[opc_start+i+1] =~ Regexp.new("[0-9A-F]+")
+ kk = instruct[opc_start+i+1].delete("()").to_i(16)
+ format += "|K"
+ end
+ end
+ if instruct[opc_start+i+1] =~ Regexp.new("\\(.+\\)")
+ format += "i";
+ end
+ end
+
+ # Output instruction
+ opcode = mnemo_list.rindex(format).to_i
+ mnemo = instruct[2];
+
+ case format
+ when "NOP", "HALT", "RET", "RETI"
+ 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", "ADD|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"
+ 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", "ADD|R|K", "AND|R|K", "OR|R|K", "XOR|R|K", "CMP|R|K"
+ 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|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"
+ 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])
+ 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 "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("Error in line %d: Not yet implemented %s", 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
+
+ filename = format("rom_%s.vhdl.snip", PROJECT_NAME)
+ file = File.open(filename, "w")
+
+ file.puts format("ENTITY %s IS\n", 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", ENTITY_ADDR_TYPE)
+ file.puts format("\tdout\t\t: out %s\n", ENTITY_DATA_TYPE)
+ file.puts format("\t);\n")
+ file.puts format("END %s;\n", ENTITY_NAME)
+ file.puts format("\n")
+ file.puts format("ARCHITECTURE %s OF %s IS \n", PROJECT_NAME, ENTITY_NAME)
+ file.puts format("\n")
+ file.puts format("\ttype instruction_rom_t is array (0 to %d) of %s;\n", pc-1, ENTITY_DATA_TYPE)
+ file.puts format("\n")
+ file.puts format("\tconstant instruction_rom : instruction_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;
+ 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 <= instruction_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("ROM file written to \"%s\"\n",filename)
+ file.close
+end
+if num_errors == 0
+
+ filename = format("preinit_%s.vhdl.snip", PROJECT_NAME)
+ file = File.open(filename, "w")
+
+ file.puts format("\tsignal instruction_rom : instruction_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 < (MAX_SIZE_ROM-1)
+ file.puts "\t\t" + vhdl_trans_list[pc-1] + ", -- " + vhdl_comment_list[pc-1] + "\n"
+ for i in (pc..(MAX_SIZE_ROM-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("PREINIT file written to \"%s\"\n",filename)
+ file.close
+end
+if num_errors == 0
+ filename = format("rom_%s.tcl.snip", PROJECT_NAME)
+ file = File.open(filename, "w")
+ 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 $CSEJTAG_SHIFT_READWRITE $CSEJTAG_RUN_TEST_IDLE 0 %d \"%8.8X\"\n\n", vhdl_tcl_list[i].length, vhdl_tcl_list[i].to_i(2));
+ end;
+ puts format("TCL snippet written to \"%s\"\n",filename)
+ file.close
+end
+
+# --------------------------------------------------------
+# Output final statistics
+# --------------------------------------------------------
+if num_errors == 0
+ puts "Program uses #{pc} instruction addresses"
+ puts "No errors found"
+ exit 0
+else
+ puts "#{num_errors} errors found"
+ exit 1
+end
diff --git a/tools/jcpu/jasm.rb b/tools/jcpu/jasm.rb
new file mode 100755
index 0000000..1d8d758
--- /dev/null
+++ b/tools/jcpu/jasm.rb
@@ -0,0 +1,811 @@
+#!/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 = __dir__ + "/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]
+ mcnt = iline_member.count{|x| !x.nil?}
+ 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..mcnt][0].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..mcnt][0].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("\"")
+ for nn in (0..str.length-1)
+ value = str[nn].ord
+ obj.put_xmem(value, lc);
+ len += 1
+ end;
+ else
+ argument = item
+ 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..mcnt]
+ curr_addr = format("0x%3.3X",obj.pc)
+ opc = token
+ if iline_member[mc+1] != nil
+ op1 = op_line[0].to_s.gsub(/,+.*$/, "")
+ end
+ if iline_member[mc+2] != nil
+ op2 = op_line[1].to_s.gsub(/,+.*$/, "")
+ 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[0].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].to_i(), i)
+ end;
+ i = XROM_MAX_SIZE-1
+ file.puts format("\t\tX\"%2.2X\" -- 0x%2.2X\n", first_pass.xmem[i].to_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].to_i(), i)
+ end;
+ i = XROM_MAX_SIZE-1
+ file.puts format("\t\tX\"%2.2X\" -- 0x%2.2X\n", first_pass.xmem[i].to_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
+
diff --git a/tools/jcpu/lib/cg.inc.jsm b/tools/jcpu/lib/cg.inc.jsm
new file mode 100644
index 0000000..01c36c4
--- /dev/null
+++ b/tools/jcpu/lib/cg.inc.jsm
@@ -0,0 +1,72 @@
+; -------------------------------------------------
+; lcd.inc.jsm
+; -------------------------------------------------
+; needs xio-address equates for
+; reg_cg_char_addr: equ 0xXX ; RW
+; reg_cg_line_addr: equ 0xXX ; RW
+; reg_cg_data: equ 0xXX ; RW
+; reg_cg_ctrl: equ 0xXX ; WO
+
+; needs delay.inc.jsm
+
+; -------------------------------------------------
+cg_clr_line: push R0
+ mov R0, 2
+ xout (reg_cg_ctrl), R0
+ pop R0
+ ret
+
+; -------------------------------------------------
+cg_clr_screen: push R0
+ mov R0, 1
+ xout (reg_cg_ctrl), R0
+ pop R0
+ ret
+
+; -------------------------------------------------
+; R0 : char address
+; R1 : line address
+cg_set_addr: call cg_wait_rdy
+ xout (reg_cg_line_addr), R1
+ xout (reg_cg_char_addr), R0
+ ret
+
+; -------------------------------------------------
+; R0 : character
+cg_putchar: call cg_wait_rdy
+ xout (reg_cg_data), R0
+ ret
+
+; -------------------------------------------------
+; R1 : ptr to string
+cg_puts: push R0
+cg_p_lp: movx R0, (R1)
+ inc R1
+ tst R0
+ jz ex_cgp
+ call cg_putchar
+ jmp cg_p_lp
+ex_cgp: pop R0
+ ret
+
+; -------------------------------------------------
+; R1 : ptr to string
+cg_clr_puts: call cg_clr_line
+ call cg_puts
+ ret
+
+; -------------------------------------------------
+; R1 : ptr to string
+cg_puts_clr: call cg_puts
+ call cg_clr_line
+ ret
+
+; -------------------------------------------------
+cg_wait_rdy: push R0
+cg_wr_lp: xin R0, (reg_hwstat)
+ and R0, 0x02
+ jz cg_wr_lp
+ pop R0
+ ret
+
+; -------------------------------------------------
diff --git a/tools/jcpu/lib/cregs.inc.jsm b/tools/jcpu/lib/cregs.inc.jsm
new file mode 100644
index 0000000..06d39d9
--- /dev/null
+++ b/tools/jcpu/lib/cregs.inc.jsm
@@ -0,0 +1,7 @@
+; JCPU On-Chip register
+cpu_revision: equ 0x00 ; RO
+cpu_control: equ 0x01 ; R/W
+cpu_status: equ 0x02 ; RO
+cpu_int_ctrl: equ 0x03 ; RW
+cpu_cmem_high: equ 0x04 ; RW
+cpu_stack_high: equ 0x05 ; RW
diff --git a/tools/jcpu/lib/delays.inc.jsm b/tools/jcpu/lib/delays.inc.jsm
new file mode 100644
index 0000000..6f002ee
--- /dev/null
+++ b/tools/jcpu/lib/delays.inc.jsm
@@ -0,0 +1,64 @@
+; -------------------------------------------------
+; Delays
+; -------------------------------------------------
+delay1s: push R15
+ mov R15, 10
+loop1s: call delay100ms
+ dec R15
+ jnz loop1s
+ pop R15
+ ret
+
+delay100ms: push R15
+ mov R15, 10
+loop100ms: call delay10ms
+ dec R15
+ jnz loop100ms
+ pop R15
+ ret
+
+delay10ms: push R15
+ mov R15, 10
+loop10ms: call delay1ms
+ dec R15
+ jnz loop10ms
+ pop R15
+ ret
+
+delay1ms: push R15
+ mov R15, 10
+loop1ms: call delay100us
+ dec R15
+ jnz loop1ms
+ pop R15
+ ret
+
+delay100us: push R15
+ mov R15, 10
+loop100us: call delay10us
+ dec R15
+ jnz loop100us
+ pop R15
+ ret
+
+delay10us: push R15
+ mov R15, 99
+loop10us: nop
+ nop
+ nop
+ dec R15
+ jnz loop10us
+ pop R15
+ ret
+
+delay1us: push R15
+ mov R15, 9
+loop1us: nop
+ nop
+ nop
+ dec R15
+ jnz loop1us
+ pop R15
+ ret
+
+; -------------------------------------------------
diff --git a/tools/jcpu/lib/lcd.inc.jsm b/tools/jcpu/lib/lcd.inc.jsm
new file mode 100644
index 0000000..d2883fa
--- /dev/null
+++ b/tools/jcpu/lib/lcd.inc.jsm
@@ -0,0 +1,208 @@
+; -------------------------------------------------
+; lcd.inc.jsm
+; -------------------------------------------------
+; needs xmem-address definition for
+; - lcd_port (LCD-Base)
+
+; needs delay.inc.jsm
+
+; -------------------------------------------------
+lcd_cmd: equ 0x00
+lcd_rd: equ 0x20
+lcd_data: equ 0x40
+lcd_enable: equ 0x80
+
+LCD_CMD_Z1: equ 0x80
+LCD_CMD_Z2: equ 0xC0
+LCD_CMD_CLEAR: equ 0x01
+
+; -------------------------------------------------
+; Init LCD
+; -------------------------------------------------
+LCD_init: mov R2, 0x00
+ mov R0, 0x03
+ call _write_lcd
+ call delay10ms
+ mov R2, 0x00
+ mov R0, 0x03
+ call _write_lcd
+ call delay10ms
+
+ mov R2, 0x00
+ mov R0, 0x02
+ call _write_lcd
+ call delay1ms
+
+ ; 1. Function set: 4-Bit mode, two display lines
+ mov R0, 0x28
+ call LCD_writecmd
+
+ ; 2. Display on, no cursor
+ mov R0, 0x0C
+ call LCD_writecmd
+
+ ; 3. Cursor shift during write
+ mov R0, 0x06
+ call LCD_writecmd
+
+ ; 4. Display clear
+ mov R0, 0x01
+ call LCD_writecmd
+
+ ret
+
+; -------------------------------------------------
+; LCD_waitbsy
+; -------------------------------------------------
+LCD_waitbsy: push R0
+bsy_loop: call LCD_readstat
+ and R0, 0x80
+ jz ex_bsy
+ call delay1us
+ jmp bsy_loop
+ex_bsy: pop R0
+ ret
+
+; -------------------------------------------------
+; LCD_writecmd
+; -------------------------------------------------
+; R0 = cmd
+LCD_writeaddr:
+LCD_writecmd: push R2
+ mov R2, lcd_cmd
+ call LCD_write
+ pop R2
+ ret
+
+; -------------------------------------------------
+; LCD_putsx
+; -------------------------------------------------
+; R1 = address of null-terminated string in XMEM
+LCD_putsx: push R0
+putsx_loop: movx R0, (R1)
+ inc R1
+ tst R0
+ jz putsx_ex
+ call LCD_writechar
+ jmp putsx_loop
+putsx_ex: pop R0
+ ret
+
+; -------------------------------------------------
+; LCD_putsc
+; -------------------------------------------------
+; R1 = address of null-terminated string in CMEM
+LCD_putsc: push R0
+putsc_loop: movc R0, (R1)
+ inc R1
+ tst R0
+ jz putsc_ex
+ call LCD_writechar
+ jmp putsc_loop
+putsc_ex: pop R0
+ ret
+
+; -------------------------------------------------
+; LCD_writechar
+; -------------------------------------------------
+; R0 = char
+LCD_writedata:
+LCD_writechar: push R2
+ mov R2, lcd_data
+ call LCD_write
+ pop R2
+ ret
+
+; -------------------------------------------------
+; LCD_write
+; -------------------------------------------------
+; R0 = input
+; R2 = register
+LCD_write: call LCD_waitbsy
+ push R0
+ swap R0
+ call _write_lcd
+ pop R0
+ call _write_lcd
+ ret
+
+; -------------------------------------------------
+; LCD_readstat
+; -------------------------------------------------
+; R0 = status
+LCD_readstat: push R2
+ mov R2, lcd_cmd
+ call LCD_read
+ pop R2
+ ret
+
+; -------------------------------------------------
+; LCD_read
+; -------------------------------------------------
+; R0 = output
+; R2 = register
+LCD_read: call _read_lcd
+ swap R0
+ push R0
+ call _read_lcd
+ pop R2
+ or R0, R2
+ ret
+
+; -------------------------------------------------
+; _write
+; -------------------------------------------------
+; R0 = input
+_write_lcd: push R1
+
+ and R0, 0x0F
+ mov R1, R0
+ or R1, R2
+ xout (lcd_port), R1
+ call delay1us
+
+ mov R1, R0
+ or R1, R2
+ or R1, lcd_enable
+ xout (lcd_port), R1
+ call delay1us
+
+ mov R1, R0
+ or R1, R2
+ xout (lcd_port), R1
+ call delay1us
+
+ or R1, lcd_rd
+ xout (lcd_port), R1
+
+ pop R1
+ ret
+
+; -------------------------------------------------
+; _read
+; -------------------------------------------------
+; R0 = output
+_read_lcd: push R1
+
+ mov R1, lcd_rd
+ or R1, R2
+ xout (lcd_port), R1
+ call delay1us
+
+ mov R1, lcd_rd
+ or R1, R2
+ or R1, lcd_enable
+ xout (lcd_port), R1
+ call delay1us
+ xin R0, (lcd_port)
+ and R0, 0x0F
+
+ mov R1, lcd_rd
+ or R1, R2
+ xout (lcd_port), R1
+ call delay1us
+
+ pop R1
+ ret
+
+
\ No newline at end of file
diff --git a/tools/jcpu/lib/mul8x8.inc.jsm b/tools/jcpu/lib/mul8x8.inc.jsm
new file mode 100644
index 0000000..2f66e2a
--- /dev/null
+++ b/tools/jcpu/lib/mul8x8.inc.jsm
@@ -0,0 +1,42 @@
+; -------------------------------------------------
+; mul8x8.inc.jsm
+; -------------------------------------------------
+
+; -------------------------------------------------
+; Parameter:
+; R0 : operand 1
+; R1 : operand 2
+; Return:
+; R0 : product low
+; R1 : product high
+mul8x8: push R2
+ push R3
+ push R4
+
+ mov R4, R1
+ mov R1, 0
+ mov R2, 0
+ mov R3, 0
+
+loop1: cmp R4, 0x01
+ jeq ende1
+
+ shr R4
+ jnc next1
+
+ add R2, R0
+ addc R3, R1
+
+next1: shl R0
+ rolc R1
+ jmp loop1
+
+ende1: add R0, R2
+ addc R1, R3
+
+ pop R4
+ pop R3
+ pop R2
+ ret
+
+; -------------------------------------------------
diff --git a/tools/jcpu/lib/uart.inc.jsm b/tools/jcpu/lib/uart.inc.jsm
new file mode 100644
index 0000000..789f579
--- /dev/null
+++ b/tools/jcpu/lib/uart.inc.jsm
@@ -0,0 +1,58 @@
+; -------------------------------------------------
+; uart.inc.jsm
+; -------------------------------------------------
+; needs xmem-address definition for
+; - uart_status (Status register)
+; - uart_data (Data register)
+UART_TX_EMPTY: equ 0x01
+UART_TX_FULL: equ 0x02
+UART_TX_CMPL: equ 0x04
+UART_RX_PRESENT: equ 0x10
+
+; -------------------------------------------------
+; uart_puts
+; -------------------------------------------------
+; R1 : ptr to string
+uart_puts: push R0
+u_p_lp: movx R0, (R1)
+ inc R1
+ tst R0
+ jz ex_ugp
+ call uart_putchar
+ jmp u_p_lp
+ex_ugp: pop R0
+ ret
+
+
+; -------------------------------------------------
+; uart_putchar
+; -------------------------------------------------
+; R0 = input
+uart_putchar: jmp sout
+
+; -------------------------------------------------
+; sout
+; -------------------------------------------------
+; R0 = input
+sout: push R1
+sout1: xin R1, (uart_status)
+ and R1, UART_TX_FULL
+ jnz sout1
+ xout (uart_data), R0
+ pop R1
+ ret
+
+; -------------------------------------------------
+; sin
+; -------------------------------------------------
+; R0 = output
+sin: push R1
+sin1: xin R1, (uart_status)
+ and R1, UART_RX_PRESENT
+ jnz sin1
+ xin R0, (uart_data)
+ pop R1
+ ret
+
+; -------------------------------------------------
+
diff --git a/tools/jcpu/lib/utils.inc.jsm b/tools/jcpu/lib/utils.inc.jsm
new file mode 100644
index 0000000..f354d7c
--- /dev/null
+++ b/tools/jcpu/lib/utils.inc.jsm
@@ -0,0 +1,32 @@
+; -------------------------------------------------
+; utils.inc.jsm
+; -------------------------------------------------
+
+
+; -------------------------------------------------
+; Parameter
+; R0 : Bin value in lower nibble
+; Return
+; R0 : Hex character representing lower nibble
+nibble2hex: and R0, 0x0F
+ cmp R0, 0x0A
+ jlt isNum1
+ add R0, 0x07
+isNum1: add R0, 0x30
+ ret
+
+; -------------------------------------------------
+; Parameter
+; R0 : Bin value
+; Return
+; R0 : Hex character high
+; R1 : Hex character low
+bin2hex: push R0
+ call nibble2hex
+ mov R1, R0
+ pop R0
+ swap R0
+ call nibble2hex
+ ret
+
+; -------------------------------------------------
diff --git a/tools/jcpu/opc.list b/tools/jcpu/opc.list
new file mode 100644
index 0000000..59b3cfa
--- /dev/null
+++ b/tools/jcpu/opc.list
@@ -0,0 +1,64 @@
+0 NOP
+1 HALT
+2 MOV|R|R
+3 MOV|R|K
+4 MOVX|R|Ri
+5 MOVX|R|Ki
+6 MOVX|Ri|R
+7 MOVX|Ri|K
+8 MOVX|Ki|R
+9 MOVC|R|Ri
+10 MOVC|R|Ki
+11 MOVC|Ri|R
+12 MOVC|Ri|K
+13 MOVC|Ki|R
+14 CMP|R|R
+15 CMP|R|K
+16 ADD|R|R
+17 ADD|R|K
+18 ADDC|R|R
+19 ADDC|R|K
+20 SUB|R|R
+21 SUB|R|K
+22 SUBC|R|R
+23 SUBC|R|K
+24 AND|R|R
+25 AND|R|K
+26 OR|R|R
+27 OR|R|K
+28 XOR|R|R
+29 XOR|R|K
+30 SHL|R
+31 SHR|R
+32 ROL|R
+33 ROR|R
+34 ROLC|R
+35 RORC|R
+36 XOUT|Ki|R
+37 XOUT|Ri|K
+38 COUT|Ki|R
+39 COUT|Ri|K
+40 XIN|R|Ki
+41 CIN|R|Ki
+42 SWAP|R
+43 SETC
+44 UNDEF
+45 UNDEF
+46 SUB|K|R
+47 SUBC|K|R
+48 JMP|K
+49 JZ|K
+50 JNZ|K
+51 JC|K
+52 JNC|K
+53 JLT|K
+54 JGT|K
+55 JLE|K
+56 JGE|K
+57 JEQ|K
+58 JNE|K
+59 CALL|K
+60 PUSH|R
+61 POP|R
+62 RET
+63 RETI
diff --git a/tools/jcpu/regx.rb b/tools/jcpu/regx.rb
new file mode 100755
index 0000000..47775c9
--- /dev/null
+++ b/tools/jcpu/regx.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+st = "\033[7m"
+en = "\033[m"
+
+ while TRUE
+ print "str> "
+ STDOUT.flush
+ str = gets
+ break if not str
+ str.chop!
+ print "pat> "
+ STDOUT.flush
+ re = gets
+ break if not re
+ re.chop!
+ str.gsub! re, "#{st}\\{en}"
+ print str, "\n"
+end
+print "\n"
diff --git a/tools/jcpu/rom.tcl.tpl b/tools/jcpu/rom.tcl.tpl
new file mode 100644
index 0000000..9f5c0dc
--- /dev/null
+++ b/tools/jcpu/rom.tcl.tpl
@@ -0,0 +1,61 @@
+# ----------------------------------------------------------------------
+# Project: JCPU, a portable 8-bit RISC CPU written in VHDL
+# This file: The ROM file for upload to target over JTAG
+#
+# 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
+#
+# ---------------------------------------------------------------------
+
+# ---------------------------------------------------------------------
+# For Chipscope 9.1
+# ---------------------------------------------------------------------
+# Source JTAG/TCL frame work
+cd $env(CHIPSCOPE)\\bin\\nt
+source csejtag.tcl
+
+namespace import ::chipscope::*
+
+# Platform USB Cable
+set PLATFORM_USB_CABLE_ARGS [list "port=USB2" "frequency=6000000"]
+# frequency="24000000 | 12000000 | 6000000 | 3000000 | 1500000 | 750000"
+
+# Create session
+set handle [::chipscope::csejtag_session create 0]
+
+# Open JTAG and lock
+set open_result [::chipscope::csejtag_target open $handle $CSEJTAG_TARGET_PLATFORMUSB 0 $PLATFORM_USB_CABLE_ARGS]
+set lock_result [::chipscope::csejtag_target lock $handle 1000]
+
+set devlist [::chipscope::csejtag_tap autodetect_chain $handle $CSEJTAG_SCAN_DEFAULT]
+
+# Get Device ID
+set devtype "Virtex-4SX"
+set devid 2
+set irlength [::chipscope::csejtag_tap get_irlength $handle $devid]
+set idcode [::chipscope::csejtag_tap get_device_idcode $handle $devid]
+
+set CSE_OP $CSEJTAG_SHIFT_READWRITE
+set CSE_ES $CSEJTAG_RUN_TEST_IDLE
+
+# Write Program
+# JASM_ROM_INSERT_HERE
+
+::chipscope::csejtag_target unlock $handle
+::chipscope::csejtag_target close $handle
+::chipscope::csejtag_session destroy $handle
+exit
diff --git a/tools/jcpu/templates.rb b/tools/jcpu/templates.rb
new file mode 100755
index 0000000..632f11c
--- /dev/null
+++ b/tools/jcpu/templates.rb
@@ -0,0 +1,44 @@
+#!/usr/bin/env ruby
+
+
+template = <<'END'
+ -- (tv #1342) read output FIFO
+ (
+ cycles => 1,
+ cm_i => bus_read_init(addr => ADDR_KS_OFIFO_DOUT),
+ sep => msg(""),
+ cm_o => bus_no_ack,
+ irq => (others => '0')
+ ),
+
+ -- (tv #1343) wait while FIFO is read
+ (
+ cycles => 2,
+ cm_i => bus_wait_ack,
+ sep => msg(""),
+ cm_o => bus_no_ack,
+ irq => (others => '0')
+ ),
+
+ -- (tv #1343) wait for ack
+ (
+ cycles => 1,
+ cm_i => bus_wait_ack,
+ sep => msg(""),
+ cm_o => bus_read_ack(dat => #{exp_data}),
+ irq => (others => '0')
+ ),
+
+END
+
+puts "KS-128 testvectors:\n"
+puts "\n" * 3
+
+
+0.upto(10) { |sk_no|
+ 3.downto(0) { |sl_no|
+ exp_data = "slice_32(TC1_SUBKEYS(#{sk_no}), #{sl_no})"
+ t = template.gsub(/"/, '\\"')
+ puts eval("format(\"#{t}\")")
+ }
+}
diff --git a/tools/jcpu/xrom.vhd.tpl b/tools/jcpu/xrom.vhd.tpl
new file mode 100644
index 0000000..5f11f86
--- /dev/null
+++ b/tools/jcpu/xrom.vhd.tpl
@@ -0,0 +1,32 @@
+-------------------------------------------------------------------------
+-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
+-- This file: The ROM file for use in your VHDL design
+--
+-- 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
+--
+--------------------------------------------------------------------------
+
+LIBRARY ieee;
+use IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+library work;
+use work.cpu_pkg.all;
+
+-- JASM_ROM_INSERT_HERE
+
diff --git a/tools/jcpu/xrom_ld.vhd.tpl b/tools/jcpu/xrom_ld.vhd.tpl
new file mode 100644
index 0000000..696487f
--- /dev/null
+++ b/tools/jcpu/xrom_ld.vhd.tpl
@@ -0,0 +1,151 @@
+-------------------------------------------------------------------------
+-- Project: JCPU, a portable 8-bit RISC CPU written in VHDL
+-- This file: loadable ROM
+--
+-- 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
+--
+--------------------------------------------------------------------------
+
+LIBRARY ieee;
+use IEEE.STD_LOGIC_1164.ALL;
+USE ieee.numeric_std.ALL;
+
+library UNISIM;
+use UNISIM.VComponents.all;
+
+library work;
+use work.cpu_pkg.all;
+
+ENTITY xrom IS
+ Port (
+ clk : in STD_LOGIC;
+ ce : in STD_LOGIC;
+ addr : in dmem_addr_t;
+ dout : out dmem_data_t
+ );
+
+END xrom;
+
+ARCHITECTURE loadable OF xrom IS
+
+ -- JASM_ROM_INSERT_HERE
+
+ signal jtag_ld_clk : STD_LOGIC;
+ signal jtag_ld_we : STD_LOGIC;
+ signal jtag_ld_addr : dmem_addr_t;
+ signal jtag_ld_dout : dmem_data_t;
+ signal jtag_ld_din : dmem_data_t;
+ signal bs_rst, bs_sel, bs_shift, bs_tdi, bs_tdo : std_logic;
+ signal bs_capture, bs_clk0, bs_clk1, bs_update0, bs_update1 : std_logic;
+ signal user_regi, user_rego : unsigned (15 downto 0);
+ constant id : unsigned (15 downto 0) := X"BEEF";
+
+begin
+
+--------------------------------------------------------------------------
+-- Virtex-4: JTAG Loader
+--------------------------------------------------------------------------
+ i00_BUFG : BUFG
+ port map
+ (
+ O => bs_clk1,
+ I => bs_clk0
+ );
+
+ i01_BUFG : BUFG
+ port map
+ (
+ O => bs_update1,
+ I => bs_update0
+ );
+
+ BSCAN_VIRTEX4_inst2 : BSCAN_VIRTEX4
+ generic map
+ (
+ JTAG_CHAIN => 2 -- Value to set BSCAN site of device. Possible values: (1,2,3 or 4)
+ )
+ port map
+ (
+ CAPTURE => bs_capture, -- CAPTURE output from TAP controller
+ DRCK => bs_clk0, -- Data register output for USER functions
+ RESET => bs_rst, -- Reset output from TAP controller
+ SEL => bs_sel, -- USER active output
+ SHIFT => bs_shift, -- SHIFT output from TAP controller
+ TDI => bs_tdi, -- TDI output from TAP controller
+ UPDATE => bs_update0, -- UPDATE output from TAP controller
+ TDO => bs_tdo -- Data input for USER function
+ );
+
+ jtag_ld_addr <= user_regi(user_regi'left downto user_regi'left-dmem_data_t'length+1);
+ jtag_ld_din <= user_regi(dmem_data_t'left downto 0);
+ jtag_ld_clk <= bs_update1;
+ jtag_ld_we <= bs_sel;
+
+sipo:
+ process (bs_rst, bs_clk1, bs_tdi, bs_shift)
+ begin
+ if bs_rst = '1' then
+ user_regi <= (others => '0');
+ elsif rising_edge(bs_clk1) then
+ if bs_shift = '1' then
+ user_regi <= bs_tdi & user_regi(user_regi'left downto 1);
+ end if;
+ end if;
+ end process;
+
+piso:
+ process (bs_rst, bs_clk1, bs_shift, user_rego)
+ begin
+ bs_tdo <= user_rego(0);
+ if bs_rst = '1' then
+ user_rego <= (others => '0');
+ elsif rising_edge(bs_clk1) then
+ if bs_shift = '1' then
+ user_rego <= user_rego(0) & user_rego(user_rego'left downto 1);
+ else
+ user_rego <= (user_rego'left downto dmem_data_t'length => '0') & jtag_ld_dout;
+-- user_rego <= id;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+-- ROM Read/Write
+--------------------------------------------------------------------------
+PROM_READ:
+ process(clk, ce)
+ begin
+ if rising_edge(clk) and ce = '1' then
+ dout <= xmem_rom(to_integer(addr));
+ end if;
+ end process;
+
+PROM_WRITE:
+ process(jtag_ld_clk, jtag_ld_we)
+ begin
+ if rising_edge(jtag_ld_clk) then
+ if jtag_ld_we = '1' then
+ xmem_rom(to_integer(jtag_ld_addr)) <= jtag_ld_din;
+ else
+ jtag_ld_dout <= xmem_rom(to_integer(jtag_ld_addr));
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------
+end loadable;
diff --git a/tools/mips/flashgen b/tools/mips/flashgen
new file mode 100755
index 0000000..7eeb8d3
Binary files /dev/null and b/tools/mips/flashgen differ
diff --git a/tools/mips/flashgen_tlb b/tools/mips/flashgen_tlb
new file mode 100755
index 0000000..6a2ec5e
Binary files /dev/null and b/tools/mips/flashgen_tlb differ
diff --git a/tools/mips/packhex b/tools/mips/packhex
new file mode 100755
index 0000000..23148f2
Binary files /dev/null and b/tools/mips/packhex differ
diff --git a/tools/mips/ramgen b/tools/mips/ramgen
new file mode 100755
index 0000000..76f517f
Binary files /dev/null and b/tools/mips/ramgen differ
diff --git a/tools/mips/romgen b/tools/mips/romgen
new file mode 100755
index 0000000..16bef3c
Binary files /dev/null and b/tools/mips/romgen differ