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