Commit 1aeaf00b authored by Roberto Hexsel's avatar Roberto Hexsel

fixed IO address decoding for FPGA

parent 0381d09c
This diff is collapsed.
......@@ -2,6 +2,7 @@
# set -x
if [ ! -v tree ] ; then
# you must set the location of the cMIPS root directory in the variable tree
# tree=${HOME}/cMIPS
......@@ -54,17 +55,18 @@ x_ROM_SIZE=$(sed -n '/x_INST_MEM_SZ/s/.*:= x"\(.*\)".*$/\1/p' $tree/vhdl/package
ROM_SZ=$((16#$x_ROM_SIZE))
mif=ROM.mif
tmp=ROM.tmp
mips-objdump -z -D -EL --section .text $elf |\
sed -e '1,6d' -e '/^$/d' -e '/^ /!d' -e 's:\t: :g' -e 's#^ *\([a-f0-9]*\): *\(........\) *\(.*\)$#\2;#' |\
awk 'BEGIN{c='$ROM_BASE';} //{ printf "%d : %s\n",c,$1 ; c=c+1; }' > xxxx
sed -e '1,6d' -e '/^$/d' -e '/^ /!d' -e 's:\t: :g' \
-e 's#^ *\([a-f0-9]*\): *\(........\) *\(.*\)$#\2;#' |\
awk 'BEGIN{c='$ROM_BASE';} //{ printf "%d : %s\n",c,$1 ; c=c+1; }' > $tmp
echo -e "\n-- cMIPS code\n\nDEPTH=${ROM_SZ};\nWIDTH=32;\n" > $mif
echo -e "ADDRESS_RADIX=DEC;\nDATA_RADIX=HEX;\nCONTENT BEGIN" >> $mif
cat xxxx >> $mif
cat $tmp >> $mif
echo "END;" >> $mif
rm -f xxxx
......@@ -79,17 +81,21 @@ RAM_SZ=$((16#$x_RAM_SIZE))
mif=RAM.mif
tmp=RAM.tmp
mips-objdump -z -D -EL --section .data --section .rodata --section rodata1 --section .data1 --section .sdata --section .lit8 --section .lit4 --section .sbss --section .bss $elf |\
sed -e '1,6d' -e '/^$/d' -e '/^ /!d' -e 's:\t: :g' -e 's#^ *\([a-f0-9]*\): *\(........\) *\(.*\)$#\2;#' |\
awk 'BEGIN{c='$RAM_BASE';} //{ printf "%d : %s\n",c,$1 ; c=c+1; }' > xxxx
sed -e '1,6d' -e '/^$/d' -e '/^ /!d' -e 's:\t: :g' \
-e 's#^ *\([a-f0-9]*\): *\(........\) *\(.*\)$#\2;#' |\
awk 'BEGIN{c='$RAM_BASE';} //{ printf "%d : %s\n",c,$1 ; c=c+1; }' > $tmp
echo -e "\n-- cMIPS data\n\nDEPTH=${RAM_SZ};\nWIDTH=32;\n" > $mif
echo -e "ADDRESS_RADIX=DEC;\nDATA_RADIX=HEX;\nCONTENT BEGIN" >> $mif
cat xxxx >> $mif
cat $tmp >> $mif
echo "END;" >> $mif
rm -f xxxx
#
rm -f {ROM,RAM}.tmp
exit 0
......@@ -2,6 +2,7 @@
##== synthesis version of startup code ===========================
##
## simple startup code for synthesis
##
.include "cMIPS.s"
.text
......@@ -20,21 +21,75 @@
## reset leaves processor in kernel mode, all else disabled
##
_start: nop
li $k0, 0x10000000
mtc0 $k0, cop0_STATUS
li $k0, MMU_WIRED
# get physical page number for 2 pages at the bottom of RAM, for .data
# needed so systems without a page table will not break
# read TLB[4] and write it to TLB[2]
li $k0, 4
mtc0 $k0, cop0_Index
ehb
tlbr
li $k1, 2
mtc0 $k1, cop0_Index
ehb
tlbwi
# then set another mapping onto TLB[4], to avoid replicated entries
li $a0, ( (x_DATA_BASE_ADDR + 8*4096) >>12 )
sll $a2, $a0, 12 # tag for RAM[8,9] double-page
mtc0 $a2, cop0_EntryHi
li $a0, ((x_DATA_BASE_ADDR + 8*4096) >>12 )
sll $a1, $a0, 6 # RAM[8] (even)
ori $a1, $a1, 0b00000000000000000000000000000111 # ccc=0, d,v,g1
mtc0 $a1, cop0_EntryLo0
li $a0, ( (x_DATA_BASE_ADDR + 9*4096) >>12 )
sll $a1, $a0, 6 # RAM[9] (odd)
ori $a1, $a1, 0b00000000000000000000000000000111 # ccc=0, d,v,g1
mtc0 $a1, cop0_EntryLo1
# and write it to TLB[4]
li $k0, 4
mtc0 $k0, cop0_Index
tlbwi
# pin down first four TLB entries: ROM[0], RAM[0], stack and I/O
li $k0, 4
mtc0 $k0, cop0_Wired
# initialize SP at top of RAM: ramTop - 16
li $sp, ((x_DATA_BASE_ADDR+x_DATA_MEM_SZ) - 16)
# set STATUS, cop0, hw interrupt IRQ7,IRQ6,IRQ5 enabled, user mode
li $k0, 0x1000e011
mtc0 $k0, cop0_STATUS
j main
nop
##
## signal normal program ending
##
exit:
_exit: j exit # wait forever
_exit: la $k0, HW_dsp7seg_addr # 7 segment display
li $k1, 0x0311 # display .1.1
sw $k1, 0($k0) # write to 7 segment display
j exit # wait forever
nop
.end _start
##
##================================================================
## exception vector_0000 TLBrefill
##
.org x_EXCEPTION_0000,0
_excp_0000:
la $k0, HW_dsp7seg_addr # 7 segment display
......@@ -42,15 +97,26 @@ _excp_0000:
sw $k1, 0($k0) # write to 7 segment display
h0000: j h0000 # wait forever
nop
.org x_EXCEPTION_0100,0
##
##================================================================
## exception vector_0100 Cache Error (hw not implemented)
## print CAUSE and stop simulation
##
.org x_EXCEPTION_0100,0
_excp_0100:
la $k0, HW_dsp7seg_addr # 7 segment display
li $k1, 0x0388 # display .8.8
sw $k1, 0($k0) # write to 7 segment display
h0100: j h0100 # wait forever
nop
##
##================================================================
## handler for all exceptions except interrupts and TLBrefill
##
.org x_EXCEPTION_0180,0
_excp_0180:
la $k0, HW_dsp7seg_addr # 7 segment display
......@@ -58,7 +124,12 @@ _excp_0180:
sw $k1, 0($k0) # write to 7 segment display
h0180: j h0180 # wait forever
nop
##
##===============================================================
## interrupt handlers at exception vector 0200
##
.org x_EXCEPTION_0200,0
_excp_0200:
la $k0, HW_dsp7seg_addr # 7 segment display
......@@ -67,7 +138,12 @@ _excp_0200:
h0200: j h0200 # wait forever
nop
.org x_EXCEPTION_BFC0,0
##
##================================================================
## exception vector_BFC0 NMI or soft-reset
##
.org x_EXCEPTION_BFC0,0
_excp_BFC0:
la $k0, HW_dsp7seg_addr # 7 segment display
li $k1, 0x0355 # display .5.5
......
#include "cMIPS.h"
typedef struct control { // control register fields (uses only ls byte)
int ign : 24, // ignore uppermost bits
rts : 1, // Request to Send
ign2 : 2, // bits 6,5 ignored
intTX : 1, // interrupt on TX buffer empty (bit 4)
intRX : 1, // interrupt on RX buffer full (bit 3)
speed : 3; // 4,8,16..256 tx-rx clock data rates (bits 0..2)
} Tcontrol;
typedef struct status { // status register fields (uses only ls byte)
int s;
// int ign : 24, // ignore uppermost bits
// ign7 : 1, // ignored (bit 7)
// txEmpty : 1, // TX register is empty (bit 6)
// rxFull : 1, // octet available from RX register (bit 5)
// int_TX_empt: 1, // interrupt pending on TX empty (bit 4)
// int_RX_full: 1, // interrupt pending on RX full (bit 3)
// ign2 : 1, // ignored (bit 2)
// framing : 1, // framing error (bit 1)
// overun : 1; // overun error (bit 0)
} Tstatus;
#define RXfull 0x00000020
#define TXempty 0x00000040
typedef union ctlStat { // control + status on same address
Tcontrol ctl; // write-only
Tstatus stat; // read-only
} TctlStat;
typedef union data { // data registers on same address
int tx; // write-only
int rx; // read-only
} Tdata;
typedef struct serial {
TctlStat cs;
Tdata d;
} Tserial;
#if 0
char s[32]; // = "the quick brown fox jumps over the lazy dog";
#else
// char s[32]; // = " ";
#endif
int main(void) { // receive a string through the UART serial interface
// and write it to the LCD display
//
// read a key from keypad and write it to the LCD display
//
int main(void) {
int i;
volatile int state;
volatile Tserial *uart; // tell GCC not to optimize away code
volatile Tstatus status;
Tcontrol ctrl;
int c, k, s;
LCDinit();
......
......@@ -33,7 +33,7 @@ end register32;
architecture functional of register32 is
begin
process(clk, rst, ld)
process(clk, rst)
variable state: reg32;
begin
if rst = '0' then
......@@ -67,7 +67,7 @@ end registerN;
architecture functional of registerN is
begin
process(clk, rst, ld)
process(clk, rst)
variable state: std_logic_vector(NUM_BITS-1 downto 0);
begin
if rst = '0' then
......@@ -138,27 +138,26 @@ entity countNup is
end countNup;
architecture functional of countNup is
signal count: std_logic_vector(NUM_BITS downto 0);
begin
process(clk, rst, ld)
process(clk, rst)
constant ZERO : std_logic_vector(NUM_BITS downto 0) := (others => '0');
variable count: std_logic_vector(NUM_BITS downto 0);
begin
if rst = '0' then
count := ZERO;
else
if rising_edge(clk) then
if ld = '1' then
count := '0' & D;
elsif en = '1' then
count := std_logic_vector(unsigned(count) + 1);
end if;
count <= ZERO;
elsif rising_edge(clk) then
if ld = '1' then
count <= '0' & D;
elsif en = '1' then
count <= std_logic_vector(unsigned(count) + 1);
end if;
end if;
Q <= count((NUM_BITS - 1) downto 0);
co <= count(NUM_BITS);
end process;
Q <= count((NUM_BITS - 1) downto 0);
co <= count(NUM_BITS);
end functional;
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......@@ -166,7 +165,6 @@ end functional;
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- ring-counter, generates four-phase internal clock, on falling-edge
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......@@ -234,6 +232,35 @@ end functional;
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- D-type flip-flop with reset
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
library IEEE; use IEEE.std_logic_1164.all;
entity FFDsimple is
port(clk, rst : in std_logic;
D : in std_logic;
Q : out std_logic);
end FFDsimple;
architecture functional of FFDsimple is
begin
process(clk, rst)
variable state: std_logic;
begin
if rst = '0' then
state := '0';
elsif rising_edge(clk) then
state := D;
end if;
Q <= state;
end process;
end functional;
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- T-type flip-flop with reset (active 0)
-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......
......@@ -852,7 +852,8 @@ begin
-- simulation aborted by instruction "wait N"
assert not(exception = exWAIT and syscall_n /= x"80000")
report LF & "ABORTED at EPC="& SLV32HEX(EPC) &
report LF & " PC="& SLV32HEX(PC) &
" EPC="& SLV32HEX(EPC) &
" bad="& SLV32HEX(BadVAddr) &
" opc="& SLV2STR(opcode) & " wait=" & SLV2STR(syscall_n(7 downto 0)) &
" instr=" & SLV32HEX(RF_instruction) &
......
......@@ -66,9 +66,10 @@ end behavioral;
-- ++ from_stdin +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- peripheral: to_stdout
-- print a signle character to stdout
-- peripheral: print_data
-- print an integer to stdout, 32bit hexadecimal
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
library IEEE;
use IEEE.std_logic_1164.all;
......@@ -76,40 +77,36 @@ use IEEE.numeric_std.all;
use std.textio.all;
use work.p_wires.all;
entity to_stdout is
entity print_data is
port (rst : in std_logic;
clk : in std_logic;
sel : in std_logic;
wr : in std_logic;
data : in std_logic_vector);
end to_stdout;
data : in reg32);
end print_data;
architecture behavioral of print_data is
architecture behavioral of to_stdout is
file output : text open write_mode is "STD_OUTPUT";
begin
U_WRITE_OUT: process(clk,sel)
U_WRITE_OUT: process(sel,clk)
variable msg : line;
begin
if falling_edge(clk) and sel = '0' then
if (data(7 downto 0) = x"00") or (data(7 downto 0) = x"0a") then
writeline( output, msg );
else
write(msg, character'val(to_integer( unsigned(data(7 downto 0)))));
end if;
write ( msg, string'(SLV32HEX(data)) );
writeline( output, msg );
end if;
end process U_WRITE_OUT;
end behavioral;
-- ++ to_stdout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++*
end behavioral;
-- ++ print_data +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- peripheral: print_data
-- print an integer to stdout, 32bit hexadecimal
-- peripheral: to_stdout
-- print a signle character to stdout
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
library IEEE;
use IEEE.std_logic_1164.all;
......@@ -117,31 +114,34 @@ use IEEE.numeric_std.all;
use std.textio.all;
use work.p_wires.all;
entity print_data is
entity to_stdout is
port (rst : in std_logic;
clk : in std_logic;
sel : in std_logic;
wr : in std_logic;
data : in reg32);
end print_data;
architecture behavioral of print_data is
data : in std_logic_vector);
end to_stdout;
architecture behavioral of to_stdout is
file output : text open write_mode is "STD_OUTPUT";
begin
U_WRITE_OUT: process(sel,clk)
U_WRITE_OUT: process(clk,sel)
variable msg : line;
begin
if falling_edge(clk) and sel = '0' then
write ( msg, string'(SLV32HEX(data)) );
writeline( output, msg );
if (data(7 downto 0) = x"00") or (data(7 downto 0) = x"0a") then
writeline( output, msg );
else
write(msg, character'val(to_integer( unsigned(data(7 downto 0)))));
end if;
end if;
end process U_WRITE_OUT;
end behavioral;
-- ++ print_data +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- ++ to_stdout +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
......@@ -206,9 +206,9 @@ end behavioral; -- write_file_data
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-- peripheral: read_data_from_file
-- read one 32bit integer from file "input.data"
-- if not EOF then read data from file
-- else status = 1
-- on a read, return last status (EOF=1, otherwise=0)
-- if not EOF then write data to file
-- else status <= 1
-- on a read, return last status (EOF=1 or otherwise=0)
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
library IEEE;
use IEEE.std_logic_1164.all;
......@@ -286,6 +286,7 @@ end behavioral;
--++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
use work.p_wires.all;
entity do_interrupt is
......@@ -318,11 +319,11 @@ architecture behavioral of do_interrupt is
co: out std_logic);
end component countNup;
component FFD is
port(clk, rst, set : in std_logic;
component FFDsimple is
port(clk, rst : in std_logic;
D : in std_logic;
Q : out std_logic);
end component FFD;
end component FFDsimple;
signal Dlimit, Qlimit, Q: c_width;
signal ld_cnt, ld_reg, en, cnt_en, int_en, equals : std_logic;
......@@ -342,11 +343,11 @@ begin
U_COUNTER: countNup generic map (NUM_BITS)
port map (clk, rst, ld_cnt, en, START_COUNT, Q, open);
i_ena <= data_inp(31) when (sel='0' and wr='0') else int_en;
U_INTERR_EN: FFD port map (clk, rst, '1', i_ena, int_en);
c_ena <= data_inp(30) when (sel='0' and wr='0') else cnt_en;
U_COUNT_EN: FFD port map (clk, rst, '1', c_ena, cnt_en);
U_COUNT_EN: FFDsimple port map (clk, rst, c_ena, cnt_en);
i_ena <= data_inp(31) when (sel='0' and wr='0') else int_en;
U_INTERR_EN: FFDsimple port map (clk, rst, i_ena, int_en);
equals <= '1' when (Q = Qlimit(NUM_BITS-1 downto 0)) else '0';
......@@ -763,6 +764,10 @@ architecture behavioral of LCD_display is
port(clk, rst, set, D : in std_logic; Q : out std_logic);
end component FFD;
component FFDsimple is
port(clk, rst, D : in std_logic; Q : out std_logic);
end component FFDsimple;
type lcd_state is (st_init, st_idle, st_n, st_n1, st_n2, st_n3,
st_n4, st_n5, st_n6, st_n7, st_n8, st_n9, st_na, st_nb);
attribute SYN_ENCODING of lcd_state : type is "safe";
......@@ -780,12 +785,12 @@ begin
U_WAIT_ON_READS: component wait_states generic map (1)
port map (rst, clk, sel, wait1);
U_WAIT2: FFD port map (clk, rst, '1', wait1, wait2);
U_WAIT2: FFDsimple port map (clk, rst, wait1, wait2);
rdy <= not(wait1 or wait2 or waiting); -- wait for 260ns
sel_rs <= addr when sel = '0' else RS;
U_INPUT_RS: FFD port map (clk, rst, '1', sel_rs, RS);
U_INPUT_RS: FFDsimple port map (clk, rst, sel_rs, RS);
U_INPUT: registerN generic map (NUM_BITS, START_VALUE)
port map (clk, rst, sel, data_inp(NUM_BITS-1 downto 0), inp_data);
......@@ -795,12 +800,12 @@ begin
data_out(31 downto NUM_BITS) <= (others => 'X');
-- TESTING ONLY
out_data <= b"00000000" when RW = '1' else (others => 'X');
-- out_data <= LCD_DATA when RW = '1' else (others => 'Z');
-- out_data <= b"00000000" when RW = '1' else (others => 'X');
out_data <= LCD_DATA when RW = '1' else (others => 'Z');
LCD_DATA <= inp_data when RW = '0' else (others => 'Z');
LCD_RS <= RS; -- LCD register select 0=ctrl, 1=data
LCD_RS <= RS; -- LCD register select 0=ctrl, 1=data
sel_rw <= wr when sel = '0' else RW;
U_INPUT_RW: FFD port map (clk, '1', rst, sel_rw, RW);
......
......@@ -41,9 +41,9 @@ package p_MEMORY is
-- begin DO NOT change these names as several scripts depend on them --
-- you may change the values, not names neither formatting --
constant x_INST_BASE_ADDR : reg32 := x"00000000";
constant x_INST_MEM_SZ : reg32 := x"00004000";
constant x_INST_MEM_SZ : reg32 := x"00002000";
constant x_DATA_BASE_ADDR : reg32 := x"00010000";
constant x_DATA_MEM_SZ : reg32 := x"00008000";
constant x_DATA_MEM_SZ : reg32 := x"00002000";
constant x_IO_BASE_ADDR : reg32 := x"0F000000";
constant x_IO_MEM_SZ : reg32 := x"00002000";
constant x_IO_ADDR_RANGE : reg32 := x"00000020";
......@@ -64,11 +64,10 @@ package p_MEMORY is
constant IO_MEM_SZ : integer := to_integer(signed(x_IO_MEM_SZ));
constant IO_ADDR_RANGE : integer := to_integer(signed(x_IO_ADDR_RANGE));
constant IO_ADDR_MASK : integer := (0 - IO_ADDR_RANGE);
constant x_IO_ADDR_MASK : reg32 := std_logic_vector(to_signed(0 - IO_ADDR_RANGE, 32));
-- maximum number of IO devices, must be a power of two.
constant IO_MAX_NUM_DEVS : integer := 16;
constant IO_ADDR_BITS : integer := log2_ceil(IO_MAX_NUM_DEVS * IO_ADDR_RANGE);
-- I/O addresses are IO_ADDR_RANGE apart
constant IO_PRINT_ADDR : integer := IO_BASE_ADDR;
......
......@@ -698,11 +698,10 @@ begin
in_range <= (addr(HI_ADDR downto LO_ADDR) = PREFIX);
aVal <= '0' when ( cpu_i_aVal = '0' and rst = '1' and in_range ) else
aVal <= '0' when ( cpu_i_aVal = '0' and in_range ) else
'1';
i_busError <= '0' when ( cpu_i_aVal = '0' and rst = '1'
and not(in_range) ) else
i_busError <= '0' when ( cpu_i_aVal = '0' and not(in_range) ) else
'1';
end architecture behavioral;
......@@ -782,7 +781,7 @@ begin
RAM_ADDR_TOP)
);