OpenCores
URL https://opencores.org/ocsvn/tinycpu/tinycpu/trunk

Subversion Repositories tinycpu

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 38 to Rev 39
    Reverse comparison

Rev 38 → Rev 39

/tinycpu/trunk/testbench/top_tb.vhd
71,8 → 71,10
variable err_cnt: integer :=0;
begin
-- hold reset state for 100 ns.
Reset <= '0';
wait for 10 ns;
Reset <= '1';
wait for 20 ns;
wait for 200 ns;
Hold <= '1';
wait for 10 ns;
assert (HoldAck ='1') report "HoldAck not becoming high" severity error;
/tinycpu/trunk/src/bootrom.vhd
0,0 → 1,34
 
library ieee;
use ieee.std_logic_1164.all;
use IEEE.NUMERIC_STD.ALL;
 
entity bootrom is
port (CLK : in std_logic;
EN : in std_logic;
ADDR : in std_logic_vector(4 downto 0);
DATA : out std_logic_vector(15 downto 0));
end bootrom;
 
architecture syn of bootrom is
constant ROMSIZE: integer := 64;
type ROM_TYPE is array(ROMSIZE/2-1 downto 0) of std_logic_vector(15 downto 0);
signal ROM: ROM_TYPE := (x"0801", x"0a01", x"58a3", x"0600", x"0402", x"5063", x"4040", x"3007", x"1701", x"3006", x"1700", x"0e16",
x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000", x"0000");
signal rdata : std_logic_vector(15 downto 0);
begin
 
rdata <= ROM(to_integer(unsigned(ADDR)));
 
process (CLK)
begin
if (CLK'event and CLK = '1') then
if (EN = '1') then
DATA <= rdata;
end if;
end if;
end process;
 
end syn;
 
/tinycpu/trunk/src/top.vhd
63,6 → 63,14
DebugR0: out std_logic_vector(7 downto 0)
);
end component;
component bootrom is
port(
CLK : in std_logic;
EN : in std_logic;
ADDR : in std_logic_vector(4 downto 0);
DATA : out std_logic_vector(15 downto 0)
);
end component;
signal cpuaddr: std_logic_vector(15 downto 0);
signal cpuww: std_logic;
signal cpuwe: std_logic;
78,6 → 86,13
signal MemWriteEnable: std_logic;
signal MemDataIn: std_logic_vector(15 downto 0);
signal MemDataOut: std_logic_vector(15 downto 0);
 
signal BootAddress: std_logic_vector(4 downto 0);
signal BootDataIn: std_logic_vector(15 downto 0);
signal BootDataOut: std_logic_vector(15 downto 0);
signal BootDone: std_logic;
constant ROMSIZE: integer := 64;
signal counter: std_logic_vector(4 downto 0);
begin
cpu: core port map (
MemAddr => cpuaddr,
104,12 → 119,35
DataOut => MemDataOut,
Port0 => Port0
);
 
MemAddress <= cpuaddr when DMA='0' else Address;
MemWriteWord <= cpuww when DMA='0' else '1';
MemWriteEnable <= cpuwe when DMA='0' else WriteEnable;
MemDataIn <= cpumemout when DMA='0' else Data when WriteEnable='1' else "ZZZZZZZZZZZZZZZZ";
rom: bootrom port map(
clk => clock,
EN => '1',
Addr => BootAddress,
Data => BootDataOut
);
MemAddress <= cpuaddr when (DMA='0' and Reset='0') else "00000001000" & BootAddress when (Reset='1' and DMA='0') else Address;
MemWriteWord <= cpuww when DMA='0' and Reset='0' else '1' when Reset='1' and DMA='0' else '1';
MemWriteEnable <= cpuwe when DMA='0' and Reset='0' else'1' when Reset='1' and DMA='0' else WriteEnable;
MemDataIn <= cpumemout when DMA='0' and Reset='0' else Data when WriteEnable='1' else BootDataIn when Reset='1' and DMA='0' else "ZZZZZZZZZZZZZZZZ";
cpumemin <= MemDataOut;
Data <= MemDataOut when DMA='1' and WriteEnable='0' else "ZZZZZZZZZZZZZZZZ";
 
Data <= MemDataOut when DMA='1' and Reset='0' and WriteEnable='0' else "ZZZZZZZZZZZZZZZZ";
bootload: process(Clock, Reset)
begin
if rising_edge(clock) then
if Reset='0' then
counter <= "00000";
BootDone <= '0';
elsif Reset='1' and BootDone='0' then
BootAddress <= counter;
BootDataIn <= BootDataOut;
counter <= std_logic_vector(unsigned(counter) + 1);
if to_integer(unsigned(counter))>=(ROMSIZE/2-1) then
BootDone <= '1';
end if;
else
end if;
end if;
end process;
end Behavioral;
/tinycpu/trunk/docs/design.md.txt
6,7 → 6,17
4. use a small amount of "rich" instructions to do powerful things
5. 1 instruction per clock cycle
 
I/O:
I/O has been decided to use a memory mapped approach.
Howto:
 
Basically, absolute address 0-32 is reserved for ports. Right now there is only a Port0. This port is 8-bits long.
Each even address is the port address. Each odd address is the bitmap for write or read for the port below it.
 
So to make ports 7 to 4 write and 3 to 0 read, you'd assign 0xF0 to address 0x0001
 
 
 
BIG CHANGE:
So, apparently making a single-cycle CPU is extremely hard... so instead, we'll be striving for a 2-cycle CPU.
Usual cycles:
347,3 → 357,7
010: mov reg, [reg]
011: mov [reg], reg
 
 
 
 
 
/tinycpu/trunk/docs/assembler.txt
0,0 → 1,55
The assembler is really a big hack job. Basically, I didn't want to write a complex assembler in C or C++, so I decided to use Ruby's power as a DSL to create an assembler.
So ruby does all the heavy syntax stuff, and I just do a bit more meta-programming than anyone probably should.
 
Anyway, Because of how it's made, you can of course use Ruby for any kind of assembler generation such as loops or whatever. Keep in mind, that after the program file runs, it outputs machine code though..
 
A simple example file:
 
----
require "asm.rb"
 
mov r0, 0x0F
mov r1, 0x1C
and r0, r1
 
-----
 
And you run it by doing something like `ruby MyAssemblyFile.rb`.
 
If you're just wanting to write some assembly code and not worry about how my assembler works, then it's quite simple.
Just use the command above, make sure to use `require "asm.rb"` and make sure that asm.rb is in your working directory.
 
The asembler is definitely an `intel` style assembler. By that, I mean target registers are on the left, and source registers are on the right.
However, because of our unique CPU architecture, there are some interesting looking constructs.
 
For instance, to use a block as `Only execute if TR is set` you'd use:
 
mov r0, 10
mov r1, 20
cmpgt r0, r1 #reads as TR=r0 > r1
if_tr_set{
mov r0, 40
}
 
 
 
 
Also, for here is a quick lookup table for the assembly words that aren't obvious:
 
rsh -- right shift
lsh -- left shift
rro -- right rotate
lro -- left rotate
cmpgt -- compare greater than
cmpgte -- compare greater than or equal
cmplt -- compare less than
cmplte -- compare less than or equal
cmpeq -- compare equal
cmpneq -- compare not equal
 
To avoid all sorts of hell with Ruby, some assembler words must be suffixed with a _
These are listed below:
or_
and_
xor_
not_
/tinycpu/trunk/assembler/asm.rb
1,6 → 1,6
PREFIX = "MemIn <= x\"";
SUFFIX = "\";";
SEPERATOR = "\n";
PREFIX = "x\"";
SUFFIX = "\"";
SEPERATOR = ", ";
 
 
 
48,7 → 48,27
 
$iftr = 0; #0 for no condition, 1 for if TR, 2 for if not TR
$useextra = 0;
$position = 0;
 
def set_cond(o1, o2)
if $iftr==0 then
o1.cond=0;
o2.cond=0;
elsif $iftr==1 then
o1.cond=1;
o2.cond=0;
else
o1.cond=0;
o2.cond=1;
end
end
def output_op(value)
printf PREFIX + value + SUFFIX;
printf SEPERATOR;
$position+=2;
end
 
 
def mov_r8_imm8(reg,imm)
o = OpcodeByte1.new();
o.op = 0;
58,8 → 78,7
else
raise "if_tr_notset is not allowed with this opcode";
end
puts PREFIX + o.to_hex + imm.to_s(16) + SUFFIX;
puts SEPERATOR;
output_op(o.to_hex.rjust(2,"0") + imm.to_s(16).rjust(2,"0"))
end
def mov_rm8_imm8(reg,imm)
o=OpcodeByte1.new();
70,10 → 89,92
else
raise "if_tr_notset is not allowed with this opcode";
end
puts PREFIX + o.to_hex + imm.to_s(16) + SUFFIX;
puts SEPERATOR;
output_op(o.to_hex.rjust(2,"0") + imm.to_s(16).rjust(2,"0"));
end
def
 
def do_group_reg_reg(opcode,group,reg1,reg2)
o1 = OpcodeByte1.new()
o1.op=opcode;
o1.register=reg1;
o2 = OpcodeByte2.new()
o2.useextra=$useextra;
o2.reg2=reg2;
o2.reg3=OpcodeOption.new(group); #opcode group
set_cond(o1,o2)
output_op(o1.to_hex.rjust(2,"0") + o2.to_hex.rjust(2,"0"))
end
def do_subgroup_reg(opcode,group,subgroup,reg1)
o1 = OpcodeByte1.new()
o1.op=opcode;
o1.register=reg1;
o2 = OpcodeByte2.new()
o2.useextra=$useextra;
o2.reg2=OpcodeOption.new(subgroup);
o2.reg3=OpcodeOption.new(group); #opcode group
set_cond(o1,o2)
output_op(o1.to_hex.rjust(2,"0") + o2.to_hex.rjust(2,"0"))
end
 
def and_reg_reg(reg1, reg2)
do_group_reg_reg(4,0,reg1,reg2)
end;
def or_reg_reg(reg1, reg2)
do_group_reg_reg(4,1,reg1,reg2)
end;
def xor_reg_reg(reg1, reg2)
do_group_reg_reg(4,2,reg1,reg2)
end;
def not_reg_reg(reg1, reg2)
do_group_reg_reg(4,3,reg1,reg2)
end;
def lsh_reg_reg(reg1, reg2)
do_group_reg_reg(4,4,reg1,reg2)
end;
def rsh_reg_reg(reg1, reg2)
do_group_reg_reg(4,5,reg1,reg2)
end;
def lro_reg_reg(reg1, reg2)
do_group_reg_reg(4,6,reg1,reg2)
end;
def rro_reg_reg(reg1, reg2)
do_group_reg_reg(4,7,reg1,reg2)
end;
#comparisons
def cmpgt_reg_reg(reg1, reg2)
do_group_reg_reg(3,0,reg1,reg2)
end;
def cmpgte_reg_reg(reg1, reg2)
do_group_reg_reg(3,1,reg1,reg2)
end;
def cmplt_reg_reg(reg1, reg2)
do_group_reg_reg(3,2,reg1,reg2)
end;
def cmplte_reg_reg(reg1, reg2)
do_group_reg_reg(3,3,reg1,reg2)
end;
def cmpeq_reg_reg(reg1, reg2)
do_group_reg_reg(3,4,reg1,reg2)
end;
def cmpneq_reg_reg(reg1, reg2)
do_group_reg_reg(3,5,reg1,reg2)
end;
def cmpeq_reg_0(reg1)
do_group_reg_reg(3,6,reg1,Register8.new(0)) #last arg isn't used
end;
def cmpneq_reg_0(reg1)
do_group_reg_reg(3,7,reg1,Register8.new(0))
end;
 
def mov_reg_mreg(reg1, reg2)
do_group_reg_reg(5,2,reg1,reg2)
end
def mov_mreg_reg(reg1, reg2)
do_group_reg_reg(5,3,reg1,reg2)
end
def mov_reg_reg(reg1, reg2)
do_group_reg_reg(5,1,reg1,reg2)
end
 
 
def mov(arg1,arg2)
80,16 → 181,147
if arg1.kind_of? Register8 and arg2.kind_of? Integer and arg2<0x100 then
mov_r8_imm8 arg1,arg2
elsif arg1.kind_of? Array and arg2.kind_of? Integer and arg2<0x100 then
if arg1.length>1 or arg1.length<1 then
if arg1.length>1 or arg1.length<1 or not arg1[0].kind_of? Register8 then
raise "memory reference is not correct. Only a register is allowed";
end
reg=arg1[0];
mov_rm8_imm8 reg, arg2
elsif arg1.kind_of? Array and arg2.kind_of? Register8 then
if arg1.length>1 or arg1.length<1 or not arg1[0].kind_of? Register8 then
raise "memory reference is not correct. Only a register is allowed";
end
mov_mreg_reg arg1[0], arg2
elsif arg1.kind_of? Register8 and arg2.kind_of? Array then
if arg2.length>1 or arg2.length<1 or not arg2[0].kind_of? Register8 then
raise "memory reference is not correct. Only a register is allowed";
end
mov_mreg_reg arg1,arg2[0]
elsif arg1.kind_of? Register8 and arg2.kind_of? Register8 then
mov_reg_reg arg1, arg2
else
raise "No suitable mov opcode found";
end
end
def and_(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
and_reg_reg arg1,arg2
else
raise "No suitable and opcode found";
end
end
def or_(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
or_reg_reg arg1,arg2
else
raise "No suitable or opcode found";
end
end
def xor_(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
xor_reg_reg arg1,arg2
else
raise "No suitable xor opcode found";
end
end
def not_(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
not_reg_reg arg1,arg2
else
raise "No suitable not opcode found";
end
end
def rsh(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
rsh_reg_reg arg1,arg2
else
raise "No suitable rsh opcode found";
end
end
def lsh(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
lsh_reg_reg arg1,arg2
else
raise "No suitable lsh opcode found";
end
end
def rro(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
rro_reg_reg arg1,arg2
else
raise "No suitable rro opcode found";
end
end
def lro(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
lro_reg_reg arg1,arg2
else
raise "No suitable lro opcode found";
end
end
 
def cmpgt(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
cmpgt_reg_reg arg1,arg2
else
raise "No suitable cmpgt opcode found";
end
end
def cmpgte(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
cmpgte_reg_reg arg1,arg2
else
raise "No suitable cmpgte opcode found";
end
end
def cmplt(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
cmplt_reg_reg arg1,arg2
else
raise "No suitable cmplt opcode found";
end
end
def cmplte(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
cmplte_reg_reg arg1,arg2
else
raise "No suitable cmplte opcode found";
end
end
def cmpeq(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
cmpeq_reg_reg arg1,arg2
elsif arg1.kind_of? Register8 and arg2.kind_of? Integer and arg2==0 then
cmpeq_reg_0 arg1
else
raise "No suitable cmpeq opcode found";
end
end
def cmpneq(arg1,arg2)
if arg1.kind_of? Register8 and arg2.kind_of? Register8 then
cmpneq_reg_reg arg1,arg2
elsif arg1.kind_of? Register8 and arg2.kind_of? Integer and arg2==0 then
cmpneq_reg_0 arg1
else
raise "No suitable cmpneq opcode found";
end
end
 
def Label
attr_accessor :name, :pos
def initialize(name, pos)
@name=name;
@pos=pos;
end
end
$labellist={}
def label(name)
$labellist[name.to_s]=$position;
end
def lbl(name)
$labellist[name.to_s]=$position;
end
def if_tr_set
$iftr = 1
yield
108,8 → 340,32
 
 
#test code follows. Only do it here for convenience.. real usage should prefix assembly files with `require "asm.rb"`
 
 
#port0(0) is LED port0(1) is a button
 
mov r4, 1
mov r5, 0x01 #the port bitmask
mov [r4],r5
mov r3, 0
mov r2, 0x02
#poll for button
label :loop
mov r0, [r3]
and_ r0, r2 #isolate just the button at pin 2
cmpneq r0, 0
if_tr_set{
mov r1,0x10
mov [r3], 0x01
}
mov r1,0x20
mov [r1], 0x50
cmpeq r0,0
if_tr_set{
mov [r3], 0x00
}
mov ip, lbl(:loop)
 
printf("\n");
while $position<64
printf("x\"0000\", ")
$position+=2;
end
puts "\nsize:" + $position.to_s

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.