Import stack-oriented CPU design from Mercurial repository.
This commit is contained in:
commit
0da3692eb8
|
|
@ -0,0 +1,35 @@
|
|||
/.lastasm
|
||||
/program.data
|
||||
/program.dis
|
||||
/program.sym
|
||||
tmp/
|
||||
/*.lso
|
||||
/*.lst
|
||||
/*.bgn
|
||||
/*.bit
|
||||
/*.bld
|
||||
/*.drc
|
||||
/*.map
|
||||
/*.mrp
|
||||
/*.ncd
|
||||
/*.ngc
|
||||
/*.ngd
|
||||
/*.ngm
|
||||
/*.ngr
|
||||
/*.pad
|
||||
/*.par
|
||||
/*.pcf
|
||||
/*.ptwx
|
||||
/*.srp
|
||||
/*.unroutes
|
||||
/*.xwbt
|
||||
/*.xpi
|
||||
/*.xrpt
|
||||
/*_pad.csv
|
||||
/*_pad.txt
|
||||
/*_vhdl.prj
|
||||
/*_summary.xml
|
||||
/*_usage.xml
|
||||
/_xmsgs/
|
||||
/xst/
|
||||
/xlnx_auto_0_xdb/
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
DESIGN = toplevel
|
||||
TOPLEVEL = TopLevel
|
||||
ASM = asm/monitor.txt
|
||||
|
||||
NGDBUILD_FLAGS ?= -aul
|
||||
MAP_FLAGS ?= -timing -ol high -xe n -detail
|
||||
PAR_FLAGS ?= -ol high -xe n
|
||||
|
||||
ifneq ($(shell cat .lastasm 2>/dev/null),$(ASM))
|
||||
# ASM changed, rebuild program.data even if up to date
|
||||
.PHONY: program.data program.dis program.sym
|
||||
endif
|
||||
|
||||
OTHER_FILES = program.data
|
||||
|
||||
-include $(XILINX)/Makefile.common
|
||||
|
||||
program.sym program.dis: program.data
|
||||
program.data: $(ASM) $(shell ./assemble.rb --depends $(ASM)) assemble.rb
|
||||
./assemble.rb --code=program.dis --syms=program.sym \
|
||||
--origin=0 --format=hex -- $< > $@
|
||||
echo $(ASM) > .lastasm
|
||||
|
||||
clean: clean-local
|
||||
|
||||
.PHONY: clean-local
|
||||
clean-local:
|
||||
-rm -f program.data program.dis program.sym .lastasm
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// Simple 2:1 alternating (round-robin) arbiter.
|
||||
// Switches master on ACK from slave unless selected master asserts LOCK.
|
||||
// Data from slave is sent to both masters. Address and data bus widths
|
||||
// are configurable, as is granularity. Default is 32-bit addresses and
|
||||
// data with byte granularity.
|
||||
module WB_ARB_2M (CLK_I, RST_I, SELECT_O,
|
||||
|
||||
M0_ADR_I, M0_DAT_I, M0_DAT_O, M0_LOCK_I, M0_CYC_I, M0_STB_I,
|
||||
M0_WE_I, M0_SEL_I, M0_ACK_O, M0_ERR_O, M0_RTY_O,
|
||||
|
||||
M1_ADR_I, M1_DAT_I, M1_DAT_O, M1_LOCK_I, M1_CYC_I, M1_STB_I,
|
||||
M1_WE_I, M1_SEL_I, M1_ACK_O, M1_ERR_O, M1_RTY_O,
|
||||
|
||||
S_ADR_O, S_DAT_O, S_DAT_I, S_LOCK_O, S_CYC_O, S_STB_O,
|
||||
S_WE_O, S_SEL_O, S_ACK_I, S_ERR_I, S_RTY_I);
|
||||
|
||||
parameter ADDR_WIDTH = 30;
|
||||
parameter DATA_WIDTH = 32;
|
||||
parameter SEL_WIDTH = 4;
|
||||
|
||||
input CLK_I, RST_I;
|
||||
output SELECT_O;
|
||||
|
||||
input [ADDR_WIDTH-1:0] M0_ADR_I, M1_ADR_I;
|
||||
input [DATA_WIDTH-1:0] M0_DAT_I, M1_DAT_I;
|
||||
output [DATA_WIDTH-1:0] M0_DAT_O, M1_DAT_O;
|
||||
input M0_LOCK_I, M1_LOCK_I;
|
||||
input M0_CYC_I, M1_CYC_I;
|
||||
input M0_STB_I, M1_STB_I;
|
||||
input M0_WE_I, M1_WE_I;
|
||||
input [SEL_WIDTH-1:0] M0_SEL_I, M1_SEL_I;
|
||||
output M0_ACK_O, M1_ACK_O;
|
||||
output M0_ERR_O, M1_ERR_O;
|
||||
output M0_RTY_O, M1_RTY_O;
|
||||
|
||||
output [ADDR_WIDTH-1:0] S_ADR_O;
|
||||
output [DATA_WIDTH-1:0] S_DAT_O;
|
||||
input [DATA_WIDTH-1:0] S_DAT_I;
|
||||
output S_LOCK_O, S_CYC_O;
|
||||
output S_STB_O, S_WE_O;
|
||||
output [SEL_WIDTH-1:0] S_SEL_O;
|
||||
input S_ACK_I, S_ERR_I, S_RTY_I;
|
||||
|
||||
reg SELECT_O = 1'bX;
|
||||
|
||||
assign M0_DAT_O = ~SELECT_O ? S_DAT_I : 256'dX;
|
||||
assign M1_DAT_O = SELECT_O ? S_DAT_I : 256'dX;
|
||||
|
||||
assign M0_ACK_O = S_ACK_I & ~SELECT_O;
|
||||
assign M1_ACK_O = S_ACK_I & SELECT_O;
|
||||
|
||||
assign M0_ERR_O = S_ERR_I & ~SELECT_O;
|
||||
assign M1_ERR_O = S_ERR_I & SELECT_O;
|
||||
|
||||
assign M0_RTY_O = S_RTY_I & ~SELECT_O;
|
||||
assign M1_RTY_O = S_RTY_I & SELECT_O;
|
||||
|
||||
assign S_ADR_O = SELECT_O ? M1_ADR_I : M0_ADR_I;
|
||||
assign S_DAT_O = SELECT_O ? M1_DAT_I : M0_DAT_I;
|
||||
assign S_LOCK_O = SELECT_O ? M1_LOCK_I : M0_LOCK_I;
|
||||
assign S_CYC_O = SELECT_O ? M1_CYC_I : M0_CYC_I;
|
||||
assign S_STB_O = SELECT_O ? M1_STB_I : M0_STB_I;
|
||||
assign S_WE_O = SELECT_O ? M1_WE_I : M0_WE_I;
|
||||
assign S_SEL_O = SELECT_O ? M1_SEL_I : M0_SEL_I;
|
||||
|
||||
wire CYC_END = (S_ACK_I | S_ERR_I | S_RTY_I);
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
casex ({S_LOCK_O, CYC_END, M1_CYC_I, M0_CYC_I})
|
||||
4'b1XXX: SELECT_O <= SELECT_O;
|
||||
4'b0111: SELECT_O <= ~SELECT_O;
|
||||
4'b0X10: SELECT_O <= 1'b1;
|
||||
4'b0X01: SELECT_O <= 1'b0;
|
||||
4'b0XXX: SELECT_O <= SELECT_O;
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
include "include/memory-map.txt"
|
||||
|
||||
_start:
|
||||
call read_char
|
||||
call write_char
|
||||
jump _start
|
||||
|
||||
include "lib/rs232.txt"
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
irq0_mask eql 0x01
|
||||
irq1_mask eql 0x02
|
||||
irq2_mask eql 0x04
|
||||
irq3_mask eql 0x08
|
||||
irq4_mask eql 0x10
|
||||
irq5_mask eql 0x20
|
||||
irq6_mask eql 0x40
|
||||
irq7_mask eql 0x80
|
||||
|
||||
rs232_rx_irq_mask eql irq1_mask
|
||||
dma_irq_mask eql irq2_mask
|
||||
rs232_tx_irq_mask eql irq3_mask
|
||||
timer_irq_mask eql irq4_mask
|
||||
|
||||
rs232_rx_isr_addr eql irq_iadr1
|
||||
dma_isr_addr eql irq_iadr2
|
||||
rs232_tx_isr_addr eql irq_iadr3
|
||||
timer_isr_addr eql irq_iadr4
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
program_base eql 0x00000000
|
||||
program_size eql 0x00000800
|
||||
|
||||
sram_base eql 0x00100000
|
||||
sram_size eql 0x00100000
|
||||
|
||||
irq_iadr0 eql 0xFFFFFF80
|
||||
irq_iadr1 eql 0xFFFFFF84
|
||||
irq_iadr2 eql 0xFFFFFF88
|
||||
irq_iadr3 eql 0xFFFFFF8C
|
||||
irq_iadr4 eql 0xFFFFFF90
|
||||
irq_iadr5 eql 0xFFFFFF94
|
||||
irq_iadr6 eql 0xFFFFFF98
|
||||
irq_iadr7 eql 0xFFFFFF9C
|
||||
|
||||
irq_stat_ctrl eql 0xFFFFFFA0
|
||||
|
||||
irq_trigger eql 0xFFFFFFA0
|
||||
irq_polarity eql 0xFFFFFFA1
|
||||
irq_mask eql 0xFFFFFFA2
|
||||
irq_status eql 0xFFFFFFA3
|
||||
|
||||
dma_src_addr eql 0xFFFFFFC0
|
||||
dma_dst_addr eql 0xFFFFFFC4
|
||||
dma_stat_ctrl eql 0xFFFFFFC8
|
||||
|
||||
timer_counter eql 0xFFFFFFE0
|
||||
timer_reload eql 0xFFFFFFE4
|
||||
timer_tbu eql 0xFFFFFFE8
|
||||
timer_tbl eql 0xFFFFFFEC
|
||||
|
||||
dev_leds eql 0xFFFFFFF0
|
||||
dev_switches eql 0xFFFFFFF0
|
||||
dev_buttons eql 0xFFFFFFF4
|
||||
dev_display_dp eql 0xFFFFFFF5
|
||||
dev_display eql 0xFFFFFFF6
|
||||
|
||||
rs232_status eql 0xFFFFFFFE
|
||||
rs232_fifo eql 0xFFFFFFFF
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
## vim: set sw=3 expandtab:
|
||||
|
||||
# ( ... get_char store_byte -- end_char )
|
||||
# get_char: ( ... -- ... char )
|
||||
# store_byte: ( ... byte -- ... )
|
||||
decode_base64:
|
||||
push
|
||||
push
|
||||
immed 0
|
||||
immed 0
|
||||
.loop: # ( n bits // gc sb )
|
||||
rdup
|
||||
pop
|
||||
swap
|
||||
push
|
||||
swap
|
||||
push # ( gc // n bits gc sb )
|
||||
call # ( ch // n bits gc sb )
|
||||
dup; immed 10; sub
|
||||
jump .not_nl rel ne drop
|
||||
drop
|
||||
pop
|
||||
pop
|
||||
jump .loop # ( n bits // gc sb )
|
||||
.not_nl: # ( ch // n bits gc sb )
|
||||
dup; immed '='; sub
|
||||
jump .pad rel eq drop
|
||||
dup
|
||||
call decode_char # ( ch val // n bits gc sb )
|
||||
jump .invalid rel lt
|
||||
nip # ( val // n bits gc sb )
|
||||
pop
|
||||
swap
|
||||
pop # ( n val bits // gc sb )
|
||||
or
|
||||
immed -6
|
||||
rshift # ( n bits' // gc sb ) [ bits' = (bits|val)<<6 ]
|
||||
push
|
||||
immed 6
|
||||
add # ( n' // bits' gc sb ) [ n' = n + 6 ]
|
||||
dup; immed 8; sub
|
||||
jump .store rel ge # ( n' (n'-8) // bits' gc sb )
|
||||
drop
|
||||
pop
|
||||
jump .loop rel # ( n' bits' // gc sb )
|
||||
.store: # ( n' (n'-8) // bits' gc sb )
|
||||
nip
|
||||
dup # ( n'' (n'-8) // bits' gc sb ) [ n'' = n'-8 ]
|
||||
rdup
|
||||
pop
|
||||
swap # ( n'' bits' (n'-8) // bits' gc sb )
|
||||
immed 6
|
||||
add
|
||||
rshift # ( n'' byte // bits' gc sb )
|
||||
swap
|
||||
pop
|
||||
pop
|
||||
rdup
|
||||
pop # ( byte n'' bits' gc sb // sb )
|
||||
swap
|
||||
push
|
||||
swap
|
||||
push
|
||||
swap
|
||||
push # ( byte sb // n'' bits' gc sb )
|
||||
call # ( // n'' bits' gc sb )
|
||||
pop
|
||||
pop
|
||||
jump .loop # ( n'' bits' // gc sb )
|
||||
.pad: # ( ch // n bits gc sb )
|
||||
# reset accumulated state
|
||||
drop
|
||||
rdrop
|
||||
rdrop
|
||||
immed 0
|
||||
immed 0
|
||||
# continue until something non-base64 is received
|
||||
jump .loop # ( n bits // gc sb )
|
||||
.invalid: # ( ch val // n bits gc sb )
|
||||
drop
|
||||
rdrop
|
||||
rdrop
|
||||
rdrop
|
||||
rdrop
|
||||
return # ( ch // )
|
||||
|
||||
# ( val low high -- (low<=val<=high) )
|
||||
in_range:
|
||||
over
|
||||
sub
|
||||
push # ( val low // (high-low) )
|
||||
sub
|
||||
jump .too_low rel lt
|
||||
pop # ( (val-low) (high-low) // )
|
||||
sub
|
||||
jump .too_high rel gt drop
|
||||
immed 1
|
||||
return
|
||||
.too_low: # ( (val-low) // (high-low) )
|
||||
drop
|
||||
rdrop
|
||||
.too_high:
|
||||
immed 0
|
||||
return
|
||||
|
||||
decode_char:
|
||||
dup; immed 'A'; immed 'Z'
|
||||
call in_range
|
||||
jump .uc rel ne drop
|
||||
|
||||
dup; immed 'a'; immed 'z'
|
||||
call in_range
|
||||
jump .lc rel ne drop
|
||||
|
||||
dup; immed '0'; immed '9'
|
||||
call in_range
|
||||
jump .digit rel ne drop
|
||||
|
||||
dup; immed '+'; sub
|
||||
jump .plus rel eq drop
|
||||
|
||||
dup; immed '/'; sub
|
||||
jump .slash rel eq drop
|
||||
|
||||
.invalid:
|
||||
immed -1
|
||||
nip return
|
||||
|
||||
.uc:
|
||||
immed 65 # 'A' == 65, base64['A'] == 0
|
||||
sub return
|
||||
|
||||
.lc:
|
||||
immed 71 # 'a' == 97, base64['a'] == 26
|
||||
sub return
|
||||
|
||||
.digit:
|
||||
immed 4 # '0' == 48, base64['0'] == 52
|
||||
add return
|
||||
|
||||
.plus:
|
||||
immed 62
|
||||
nip return
|
||||
|
||||
.slash:
|
||||
immed 63
|
||||
nip return
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#int memcmp(const void *data, const void *base, size_t sz)
|
||||
#{
|
||||
# const uint8_t *p = (const uint8_t*)data;
|
||||
# const uint8_t *q = (const uint8_t*)base;
|
||||
#
|
||||
# while (sz-- > 0)
|
||||
# {
|
||||
# int c = *p++ - *q++;
|
||||
# if (c != 0)
|
||||
# return c;
|
||||
# }
|
||||
# return 0;
|
||||
#}
|
||||
|
||||
# ( p1 p2 sz -- diff )
|
||||
memcmp:
|
||||
jump .nonempty rel ne
|
||||
drop2
|
||||
immed 0
|
||||
nip return # ( 0 // )
|
||||
.nonempty:
|
||||
push
|
||||
dup
|
||||
push
|
||||
swap
|
||||
dup
|
||||
push # ( p2 p1 // p1 p2 sz )
|
||||
load byte
|
||||
swap
|
||||
load byte # ( [p1] [p2] // p1 p2 sz )
|
||||
sub
|
||||
jump .zero rel eq
|
||||
rdrop
|
||||
rdrop
|
||||
rdrop
|
||||
return # ( diff // )
|
||||
.zero: # ( diff // p1 p2 sz )
|
||||
drop
|
||||
pop
|
||||
immed 1
|
||||
add
|
||||
pop
|
||||
immed 1
|
||||
add
|
||||
pop
|
||||
immed 1
|
||||
sub
|
||||
jump memcpy # ( p1+1 p2+1 sz-1 // )
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
include "../include/memory-map.txt"
|
||||
|
||||
# Read from serial port w/ remote echo. Ignores CRs.
|
||||
#
|
||||
# char read_char()
|
||||
# {
|
||||
# uint32_t in;
|
||||
# char c;
|
||||
#
|
||||
# do {
|
||||
# while (((in = *(uint32_t*)rs232_fifo) & 0x100) == 0)
|
||||
# /* wait for input */;
|
||||
# c = in & 0xff;
|
||||
# } while (c == '\r');
|
||||
#
|
||||
# write_char(c);
|
||||
# return c;
|
||||
# }
|
||||
|
||||
read_char:
|
||||
immed rs232_fifo
|
||||
load
|
||||
dup; immed 0x100; and
|
||||
jump .got_char rel ne drop
|
||||
jump read_char rel drop
|
||||
.got_char:
|
||||
immed 0xff; and
|
||||
dup; immed 13; sub
|
||||
jump .ignore_cr rel eq drop
|
||||
dup
|
||||
call write_char
|
||||
return
|
||||
.ignore_cr:
|
||||
jump read_char rel drop
|
||||
|
||||
|
||||
write_char:
|
||||
dup; immed 10; sub
|
||||
jump .not_nl rel ne drop
|
||||
immed 13
|
||||
pushpc
|
||||
.not_nl:
|
||||
immed rs232_status
|
||||
load byte; immed 2; and
|
||||
jump .not_nl rel ne drop
|
||||
immed rs232_fifo
|
||||
store byte
|
||||
return
|
||||
|
||||
|
||||
newline:
|
||||
immed 10
|
||||
jump write_char
|
||||
# ^^^ Tail call
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
## Uses the built-in unsigned multiplier to do signed 32-bit multiplication:
|
||||
##
|
||||
## (x+(2**32)x[31])(y+(2**32)y[31]) =
|
||||
##
|
||||
## xy + (2**32)(x[31]y + y[31]x) + (2**64)x[31]y[31]
|
||||
##
|
||||
## Anything above bit 64 is ignored, so we just need to subtract
|
||||
##
|
||||
## x[31]y + y[31]x
|
||||
##
|
||||
## from the MSW (bits 32 to 63) of the unsigned result. The LSW is fine as-is.
|
||||
## The interface is the same as the normal 'mult' instruction.
|
||||
|
||||
# ( x y -- lsw msw )
|
||||
signed_mult:
|
||||
jump .ypos rel ge
|
||||
over
|
||||
jump .xtest rel
|
||||
.ypos:
|
||||
immed 0
|
||||
.xtest:
|
||||
push
|
||||
swap
|
||||
jump .xpos rel ge
|
||||
over
|
||||
pop
|
||||
add
|
||||
push
|
||||
.xpos:
|
||||
mult
|
||||
pop
|
||||
sub return
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
include "include/memory-map.txt"
|
||||
|
||||
_start:
|
||||
jump main
|
||||
|
||||
include "lib/rs232.txt"
|
||||
|
||||
main:
|
||||
immed 65
|
||||
dup
|
||||
call write_char #A 65
|
||||
immed 1
|
||||
add
|
||||
dup
|
||||
call write_char #B 66
|
||||
immed -1
|
||||
sub
|
||||
dup
|
||||
call write_char #C 67
|
||||
immed -1
|
||||
rshift
|
||||
immed 66
|
||||
sub
|
||||
dup
|
||||
call write_char #D 68
|
||||
immed 0
|
||||
over
|
||||
sub
|
||||
immed -1
|
||||
xor
|
||||
immed 2
|
||||
add
|
||||
dup
|
||||
call write_char #E 69
|
||||
immed 2
|
||||
add
|
||||
dup
|
||||
immed 70
|
||||
nip
|
||||
call write_char #F 70
|
||||
dup
|
||||
call write_char #G 71
|
||||
loop0:
|
||||
immed 1
|
||||
add
|
||||
dup
|
||||
call write_char #H-J 72-74
|
||||
dup
|
||||
immed 74
|
||||
sub
|
||||
jump loop0 rel lt drop
|
||||
immed 1
|
||||
add
|
||||
call write_char #K 75
|
||||
immed 76
|
||||
dup
|
||||
call write_char #L 76
|
||||
loop1:
|
||||
immed 1
|
||||
add
|
||||
dup
|
||||
call write_char #M-N 77-78
|
||||
immed 78
|
||||
over
|
||||
sub
|
||||
jump loop1 rel gt drop
|
||||
immed 1
|
||||
or
|
||||
dup
|
||||
call write_char #O 79
|
||||
immed 0b1110000
|
||||
and
|
||||
immed 0b10000
|
||||
or
|
||||
dup
|
||||
call write_char #P 80
|
||||
dup
|
||||
immed 2
|
||||
add
|
||||
push
|
||||
immed 1
|
||||
add
|
||||
call write_char #Q 81
|
||||
pop
|
||||
dup
|
||||
call write_char #R 82
|
||||
pushpc
|
||||
pushpc
|
||||
immed 15
|
||||
push
|
||||
rdrop
|
||||
pop
|
||||
pop
|
||||
sub
|
||||
add
|
||||
dup
|
||||
call write_char #S 83
|
||||
|
||||
drop
|
||||
call newline
|
||||
|
||||
# Echo input until reset / power-off
|
||||
echo:
|
||||
call read_char
|
||||
call write_char
|
||||
jump echo rel
|
||||
|
|
@ -0,0 +1,268 @@
|
|||
# vim: set sw=3 tw=80:
|
||||
|
||||
include "include/memory-map.txt"
|
||||
|
||||
export read_char
|
||||
export write_char
|
||||
export newline
|
||||
export read_hex
|
||||
export write_hex
|
||||
export puts
|
||||
export end_of_monitor
|
||||
|
||||
import decode_base64
|
||||
|
||||
start_of_monitor:
|
||||
_start:
|
||||
jump main
|
||||
|
||||
include "lib/rs232.txt"
|
||||
|
||||
to_upper:
|
||||
dup; immed 'a'; sub
|
||||
jump .not_lc rel lt drop
|
||||
dup; immed 'z'; sub
|
||||
jump .not_lc rel gt drop
|
||||
immed 32
|
||||
sub return
|
||||
.not_lc:
|
||||
return
|
||||
|
||||
start_str: byte "Stack CPU Monitor Program" 10 0
|
||||
prompt_str: byte "> " 0
|
||||
error_str: byte "ERROR" 10 0
|
||||
access_str: byte "ACCESS DENIED" 10 0
|
||||
|
||||
# Commands:
|
||||
# READ addr
|
||||
# WRITE value addr
|
||||
# STORE start_addr
|
||||
# CALL addr
|
||||
main:
|
||||
immed start_str
|
||||
call puts
|
||||
|
||||
.prompt:
|
||||
immed prompt_str
|
||||
call puts
|
||||
|
||||
.getcmd:
|
||||
call read_char
|
||||
call to_upper
|
||||
|
||||
dup; immed ' '; sub
|
||||
jump .ignore_sp rel eq drop
|
||||
dup; immed 10; sub
|
||||
jump .ignore_nl rel eq drop
|
||||
|
||||
dup; immed 'R'; sub
|
||||
jump .read rel eq drop
|
||||
dup; immed 'W'; sub
|
||||
jump .write rel eq drop
|
||||
dup; immed 'S'; sub
|
||||
jump .store rel eq drop
|
||||
dup; immed 'C'; sub
|
||||
jump .call rel eq drop
|
||||
dup; immed 35; sub
|
||||
jump .comment rel eq drop
|
||||
drop
|
||||
|
||||
.invalid:
|
||||
call newline
|
||||
immed error_str
|
||||
call puts
|
||||
jump .prompt
|
||||
|
||||
.ignore_sp:
|
||||
jump .getcmd rel drop
|
||||
.ignore_nl:
|
||||
jump .prompt rel drop
|
||||
|
||||
.expect_char:
|
||||
call read_char
|
||||
call to_upper
|
||||
sub
|
||||
jump .correct rel eq drop
|
||||
rdrop # Don't return to caller
|
||||
jump .invalid rel
|
||||
.correct:
|
||||
return
|
||||
|
||||
.read:
|
||||
drop #R
|
||||
immed 'E'; call .expect_char rel
|
||||
immed 'A'; call .expect_char rel
|
||||
immed 'D'; call .expect_char rel
|
||||
immed ' '; call .expect_char rel
|
||||
call read_hex
|
||||
immed 10; sub
|
||||
jump ..invalid rel ne drop
|
||||
load
|
||||
call write_hex
|
||||
call newline
|
||||
jump .prompt rel
|
||||
..invalid:
|
||||
jump .invalid rel drop
|
||||
|
||||
.write:
|
||||
drop #W
|
||||
immed 'R'; call .expect_char rel
|
||||
immed 'I'; call .expect_char rel
|
||||
immed 'T'; call .expect_char rel
|
||||
immed 'E'; call .expect_char rel
|
||||
immed ' '; call .expect_char rel
|
||||
call read_hex
|
||||
immed ' '; sub
|
||||
jump ..invalid1 rel ne drop
|
||||
call read_hex
|
||||
immed 10; sub
|
||||
jump ..invalid2 rel ne drop
|
||||
dup; immed start_of_monitor; sub
|
||||
jump ..ok rel lt drop
|
||||
dup; immed end_of_monitor; sub
|
||||
jump ..denied rel lt drop
|
||||
..ok:
|
||||
store
|
||||
jump .prompt
|
||||
..invalid2:
|
||||
drop
|
||||
..invalid1:
|
||||
jump .invalid rel drop
|
||||
..denied:
|
||||
drop2
|
||||
immed access_str
|
||||
call puts
|
||||
jump .prompt
|
||||
|
||||
.store:
|
||||
drop #S
|
||||
immed 'T'; call .expect_char rel
|
||||
immed 'O'; call .expect_char rel
|
||||
immed 'R'; call .expect_char rel
|
||||
immed 'E'; call .expect_char rel
|
||||
immed ' '; call .expect_char rel
|
||||
call read_hex
|
||||
immed 10; sub
|
||||
jump ..invalid rel ne drop
|
||||
immed read_char
|
||||
immed .store_byte
|
||||
call decode_base64
|
||||
drop2
|
||||
jump .prompt rel
|
||||
..invalid:
|
||||
jump .invalid rel drop
|
||||
|
||||
.store_byte: # ( buffer byte -- buffer' )
|
||||
over
|
||||
store byte
|
||||
immed 1
|
||||
add return
|
||||
|
||||
.call:
|
||||
drop #C
|
||||
immed 'A'; call .expect_char rel
|
||||
immed 'L'; call .expect_char rel
|
||||
immed 'L'; call .expect_char rel
|
||||
immed ' '; call .expect_char rel
|
||||
call read_hex
|
||||
immed 10; sub
|
||||
jump ..invalid rel ne drop
|
||||
call # expected: ( -- )
|
||||
jump .prompt rel
|
||||
..invalid:
|
||||
jump .invalid rel drop
|
||||
|
||||
.comment:
|
||||
immed 10; sub
|
||||
jump .prompt eq drop
|
||||
call read_char
|
||||
jump .comment
|
||||
|
||||
|
||||
# Reads an arbitrary number of hex digits, returning the last eight as
|
||||
# a 32-bit integer along with the following non-hex character.
|
||||
read_hex: # ( -- integer last_char )
|
||||
immed 0
|
||||
call read_char
|
||||
call to_upper
|
||||
dup; push
|
||||
dup; immed '-'; sub
|
||||
jump .after_first_char rel ne drop
|
||||
.negative:
|
||||
drop
|
||||
.get_next_char:
|
||||
call read_char
|
||||
call to_upper
|
||||
.after_first_char:
|
||||
dup; immed '0'; sub
|
||||
jump .not_hex rel lt drop
|
||||
dup; immed '9'; sub
|
||||
jump .number rel le drop
|
||||
dup; immed 'A'; sub
|
||||
jump .not_hex rel lt drop
|
||||
dup; immed 'F'; sub
|
||||
jump .letter rel le drop
|
||||
.not_hex:
|
||||
swap
|
||||
pop; immed '-'; sub
|
||||
jump .positive rel ne drop
|
||||
immed 0; swap; sub
|
||||
.positive:
|
||||
swap
|
||||
return
|
||||
.number:
|
||||
immed '0'; sub
|
||||
.merge:
|
||||
push
|
||||
immed -4; rshift
|
||||
pop
|
||||
or
|
||||
jump .get_next_char rel
|
||||
.letter:
|
||||
immed 55; sub # 55 = 'A'-10
|
||||
jump .merge rel
|
||||
|
||||
# Displays integer as eight hex digits
|
||||
write_hex: # ( integer -- )
|
||||
immed 8
|
||||
.loop:
|
||||
push
|
||||
dup
|
||||
immed -4; rshift
|
||||
push
|
||||
immed 28; rshift
|
||||
dup; immed 10; sub
|
||||
jump .letter rel ge drop
|
||||
immed '0'
|
||||
.common:
|
||||
add
|
||||
call write_char
|
||||
jump .next rel
|
||||
.letter:
|
||||
immed 10; sub
|
||||
immed 'A'
|
||||
jump .common rel
|
||||
.next:
|
||||
pop
|
||||
pop
|
||||
immed 1; sub
|
||||
jump .loop rel gt
|
||||
drop2
|
||||
return
|
||||
|
||||
include "lib/base64.txt"
|
||||
|
||||
# ( addr -- ) [ addr -> null-terminated ASCII string ]
|
||||
puts:
|
||||
dup
|
||||
load byte
|
||||
jump .nul rel eq
|
||||
call write_char
|
||||
immed 1
|
||||
add
|
||||
jump puts rel
|
||||
.nul:
|
||||
drop2
|
||||
return
|
||||
|
||||
end_of_monitor:
|
||||
|
|
@ -0,0 +1,687 @@
|
|||
#!/usr/bin/env ruby
|
||||
# vim: set sw=3 tw=80:
|
||||
require 'base64'
|
||||
|
||||
POS_INT_REGEX = /(?:0[0-7]+|0b[01]+|0x[0-9a-fA-F]+|[0-9]+)/
|
||||
|
||||
# Make sure input is treated as a signed 32-bit number
|
||||
def signed32(n)
|
||||
if n and (n < 0 or n >= 0x80000000)
|
||||
-(-n & 0xffffffff)
|
||||
else
|
||||
n
|
||||
end
|
||||
end
|
||||
|
||||
def split_immed(n)
|
||||
result = []
|
||||
|
||||
while (n < -16) || (n > 15)
|
||||
result = [ 0b10000000 | (n & 0x7f) ] + result
|
||||
n >>= 7
|
||||
end
|
||||
|
||||
[ 0b00100000 | (n & 0x1f) ] + result
|
||||
end
|
||||
|
||||
$labels = {}
|
||||
$forward_labels = {}
|
||||
|
||||
class Label
|
||||
attr_accessor :name
|
||||
def initialize(name, pc=nil)
|
||||
unless name =~ /^\.*[a-zA-Z_]\w*$/
|
||||
raise StandardError.new("Bad label name '#{name}' at #{$file}:#{$line}")
|
||||
end
|
||||
@name, @pc = name, pc
|
||||
@export, @global = false, false
|
||||
@alias = nil
|
||||
end
|
||||
|
||||
def export=(x) @export = x ? true : false; end
|
||||
def export?() @export; end
|
||||
|
||||
def global=(x) @global = x ? true : false; end
|
||||
def global?() @global; end
|
||||
|
||||
def local?() (@name =~ /^(\.+)/) ? $1.length : false; end
|
||||
def level() self.local? || 0; end
|
||||
|
||||
def pc=(x) @pc = x; end
|
||||
def pc() @alias ? @alias.pc : @pc; end
|
||||
def alias() @alias; end
|
||||
def alias?() @alias ? true : false; end
|
||||
|
||||
def Label.get(name)
|
||||
lbl = $labels[name] || $forward_labels[name]
|
||||
if not lbl
|
||||
lbl = Label.new(name)
|
||||
$forward_labels[name] = lbl
|
||||
end
|
||||
return lbl
|
||||
end
|
||||
|
||||
def Label.define(name)
|
||||
if $labels.has_key? name
|
||||
$stderr.puts "WARNING: Redefining label '#{name}'."
|
||||
end
|
||||
|
||||
lbl = $forward_labels[name] || Label.new(name)
|
||||
$forward_labels.delete name
|
||||
$labels[name] = lbl
|
||||
return lbl
|
||||
end
|
||||
|
||||
def Label.alias(label, name)
|
||||
if $labels.has_key? name
|
||||
$stderr.puts "WARNING: Redefining label '#{name}'."
|
||||
end
|
||||
|
||||
lbl = $forward_labels[name] || Label.new(name)
|
||||
lbl.instance_variable_set(:@alias, label)
|
||||
$forward_labels.delete name
|
||||
$labels[name] = lbl
|
||||
return lbl
|
||||
end
|
||||
|
||||
def Label.in_file_scope()
|
||||
old_labels, old_forwards = $labels.dup, $forward_labels.dup
|
||||
|
||||
# Local references end at file boundaries
|
||||
$labels.delete_if { |k,v| not v.global? }
|
||||
$forward_labels.delete_if { |k,v| not v.global? }
|
||||
|
||||
yield
|
||||
|
||||
# Local references end at file boundaries
|
||||
$labels.delete_if { |k,v| not v.global? }
|
||||
$forward_labels.delete_if { |k,v| not v.global? }
|
||||
|
||||
$labels = old_labels.merge($labels)
|
||||
$forward_labels = old_forwards.merge($forward_labels)
|
||||
end
|
||||
end
|
||||
|
||||
class Instruction
|
||||
def initialize(labels, pc, opcode, args)
|
||||
@labels = labels.map do |name|
|
||||
lbl = Label.define(name)
|
||||
$labels.delete_if { |k,v| v.level > lbl.level }
|
||||
lbl
|
||||
end
|
||||
|
||||
@type = opcode.downcase.to_sym
|
||||
@args = args
|
||||
@align = 1
|
||||
|
||||
valid = true
|
||||
|
||||
case @type
|
||||
when :nop, :rshift, :nip, :and, :or,
|
||||
:xor, :swap, :dup, :add, :sub
|
||||
valid = args.empty? || ((args.length == 1) && (args[0] =~ /return/i))
|
||||
@return = !args.empty?
|
||||
when :load, :store
|
||||
valid = args.empty? || ((args.length == 1) && (args[0] =~ /byte/i))
|
||||
@byte_op = !args.empty?
|
||||
when :return
|
||||
valid = args.empty?
|
||||
@type = :nop
|
||||
@return = true
|
||||
when :rdrop, :pop, :pushpc, :push, :rdup, :mult, :over, :nlz
|
||||
valid = args.empty?
|
||||
when :immed
|
||||
if (args.length == 1) and (args[0] =~ /^-?#{POS_INT_REGEX}$/)
|
||||
# Integer constant
|
||||
valid, @value = true, signed32(args[0].to_i(0))
|
||||
elsif (args.length == 1) and (args[0] =~ /^'.'$/)
|
||||
# Character constant
|
||||
valid, @value = true, args[0][1].ord
|
||||
else
|
||||
valid, @target = true, Label.get(args[0])
|
||||
end
|
||||
when :jump, :call
|
||||
@rel, @target, @cc, @drop = false, nil, :always, false
|
||||
|
||||
args.each do |arg|
|
||||
case arg
|
||||
when /^rel$/i
|
||||
@rel = true
|
||||
when /^(never|eq|lt|gt|always|ne|ge|le)$/i
|
||||
@cc = $1.downcase.to_sym
|
||||
when /^drop$/i
|
||||
@drop = true;
|
||||
else
|
||||
if @target
|
||||
raise StandardError.new("Syntax error: #{opcode} #{args.join(' ')}")
|
||||
else
|
||||
@target = Label.get(arg)
|
||||
end
|
||||
end
|
||||
end
|
||||
when :drop
|
||||
@type = :jump
|
||||
@rel = false
|
||||
@target = nil
|
||||
@cc = :never
|
||||
@drop = false
|
||||
when :drop2
|
||||
@type = :jump
|
||||
@target = nil
|
||||
@rel = false
|
||||
@cc = :never
|
||||
@drop = true
|
||||
when :merge
|
||||
valid = (args.length == 1) && (args[0] =~ /^#{POS_INT_REGEX}$/)
|
||||
@value = args[0].to_i(0) if valid
|
||||
valid &&= (@value >= 0 and @value <= 127)
|
||||
when :resb
|
||||
valid = (args.length == 1) && (args[0] =~ /^#{POS_INT_REGEX}$/)
|
||||
@immed = [ 0 ] * args[0].to_i(0) if valid
|
||||
when :align
|
||||
valid = (args.length == 1) && (args[0] =~ /^#{POS_INT_REGEX}$/)
|
||||
@align = args[0].to_i(0) if valid
|
||||
valid &&= (@align >= 1)
|
||||
when :byte
|
||||
valid = true
|
||||
@immed = []
|
||||
args.each do |arg|
|
||||
case arg
|
||||
when /^-?#{POS_INT_REGEX}$/
|
||||
v = arg.to_i(0)
|
||||
valid &&= (-128..255).member? v
|
||||
@immed << (v & 0xff) if valid
|
||||
when /^'(.)'$/
|
||||
@immed << (arg[1].ord & 0xff) if valid
|
||||
when /^".*"$/
|
||||
arg[1..-2].scan(/([^\\"])|(\\")|(\\\\)/) do |a,b,c|
|
||||
a = '"' if b
|
||||
a = '\\' if c
|
||||
@immed << (a[0].ord & 0xff)
|
||||
end
|
||||
else
|
||||
raise StandardError.new("Unsupported BYTE operand.")
|
||||
end
|
||||
end
|
||||
when :word
|
||||
valid = true
|
||||
@immed = []
|
||||
@align = 4
|
||||
args.each do |arg|
|
||||
case arg
|
||||
when /^-?#{POS_INT_REGEX}$/
|
||||
v = arg.to_i(0)
|
||||
# Convert long to unsigned chars w/ big-endian byte order
|
||||
@immed += [v].pack("N").unpack("C*")
|
||||
else
|
||||
raise StandardError.new("WORD only supports integer operands.")
|
||||
end
|
||||
end
|
||||
else
|
||||
raise StandardError.new("Syntax error: #{opcode} #{args.join(' ')}")
|
||||
end
|
||||
|
||||
if not valid
|
||||
raise StandardError.new("Invalid instruction: #{opcode} #{args.join(' ')}")
|
||||
end
|
||||
|
||||
reflow(pc)
|
||||
end
|
||||
|
||||
def reflow(pc)
|
||||
if pc >= $options[:ram_size]
|
||||
raise StandardError.new("No more room in Block RAM.")
|
||||
end
|
||||
|
||||
@align_bytes = (-pc) % @align
|
||||
@pc = pc + @align_bytes
|
||||
old_bytes = @bytes
|
||||
@labels.each { |lbl| lbl.pc = @pc }
|
||||
|
||||
if @target
|
||||
@value = signed32(@target.pc)
|
||||
|
||||
if @value
|
||||
if @rel
|
||||
# Known relative; PC of jump/call depends on immed. length
|
||||
diff = @value - (@pc + 6)
|
||||
im_size = split_immed(diff).length
|
||||
diff = @value - (@pc + im_size + 1)
|
||||
@immed = split_immed(diff)
|
||||
|
||||
if @immed.length > im_size
|
||||
im_size = @immed.length
|
||||
diff = @value - (@pc + im_size + 1)
|
||||
@immed = split_immed(diff)
|
||||
end
|
||||
|
||||
if @immed.length > im_size
|
||||
raise StandardError.new("Relative target offset won't converge!")
|
||||
end
|
||||
else
|
||||
# Absolute known address
|
||||
@immed = split_immed(@value)
|
||||
end
|
||||
else
|
||||
# Unknown address; reserve maximum space that may be required
|
||||
@immed = split_immed(-($max_pc+1))
|
||||
end
|
||||
elsif @value
|
||||
@immed = split_immed(@value)
|
||||
end
|
||||
|
||||
if @type == :align
|
||||
@bytes = 0
|
||||
elsif not @immed
|
||||
@bytes = 1
|
||||
elsif @type == :jump or @type == :call
|
||||
@bytes = @immed.length + 1
|
||||
else
|
||||
@bytes = @immed.length
|
||||
end
|
||||
|
||||
@bytes += @align_bytes
|
||||
|
||||
if old_bytes != @bytes
|
||||
$layout_changed = true
|
||||
end
|
||||
end
|
||||
|
||||
def bytes() @bytes; end
|
||||
|
||||
def finalize_target
|
||||
if @target
|
||||
@value = signed32(@target.pc)
|
||||
|
||||
if not @value
|
||||
raise StandardError.new("Unknown label: '#{@target.name}'")
|
||||
else
|
||||
if @rel
|
||||
@immed = split_immed(@value - (@pc + @bytes))
|
||||
else
|
||||
@immed = split_immed(@value)
|
||||
end
|
||||
end
|
||||
|
||||
if @type == :immed
|
||||
bytes = @immed.length
|
||||
else
|
||||
bytes = @immed.length + 1
|
||||
end
|
||||
|
||||
if @bytes < bytes
|
||||
raise StandardError.new("Insufficient space for target address.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
OPCODES = {
|
||||
:nop => 0b00000000,
|
||||
:rshift => 0b00000010,
|
||||
:add => 0b00000100,
|
||||
:sub => 0b00000110,
|
||||
:nip => 0b00001000,
|
||||
:and => 0b00001010,
|
||||
:or => 0b00001100,
|
||||
:xor => 0b00001110,
|
||||
:swap => 0b00010000,
|
||||
:dup => 0b00010010,
|
||||
:over => 0b00010100,
|
||||
:rdup => 0b00010101,
|
||||
:nlz => 0b00010110,
|
||||
:mult => 0b00010111,
|
||||
:load => 0b00011000,
|
||||
:store => 0b00011010,
|
||||
:rdrop => 0b00011100,
|
||||
:pop => 0b00011101,
|
||||
:pushpc => 0b00011110,
|
||||
:push => 0b00011111,
|
||||
:jump => 0b01000000,
|
||||
:call => 0b01100000
|
||||
}.freeze
|
||||
|
||||
CC_MAP = {
|
||||
:never => 0b000,
|
||||
:eq => 0b001,
|
||||
:lt => 0b010,
|
||||
:gt => 0b011,
|
||||
:always => 0b100,
|
||||
:ne => 0b101,
|
||||
:ge => 0b110,
|
||||
:le => 0b111
|
||||
}.freeze
|
||||
|
||||
def to_bytes
|
||||
finalize_target
|
||||
bytes = [0] * @align_bytes
|
||||
|
||||
case @type
|
||||
when :align
|
||||
# no opcode
|
||||
nil
|
||||
when :nop, :rshift, :add, :sub, :nip,
|
||||
:and, :or, :xor, :swap, :dup
|
||||
bytes << (OPCODES[@type] | (@return ? 1 : 0))
|
||||
when :load, :store
|
||||
bytes << (OPCODES[@type] | (@byte_op ? 1 : 0))
|
||||
when :rdrop, :pop, :pushpc, :push, :rdup, :mult, :over, :nlz
|
||||
bytes << OPCODES[@type]
|
||||
when :immed, :resb, :byte, :word
|
||||
bytes += @immed
|
||||
when :jump, :call
|
||||
result = OPCODES[@type]
|
||||
result |= 0b10000 if @rel
|
||||
result |= (CC_MAP[@cc]<<1) if @cc
|
||||
result |= 0b00001 if @drop
|
||||
# Insert NOPs if immed is shorter than allocated
|
||||
pad = @immed && ([0] * (@bytes - (@immed.length + 1)))
|
||||
bytes += pad if pad
|
||||
bytes += @immed if @immed
|
||||
bytes << result
|
||||
when :merge
|
||||
bytes << (0b10000000 | (@value & 0x7f))
|
||||
else
|
||||
raise StandardError.new("Don't know how to output a #{@type} opcode.")
|
||||
end
|
||||
bytes
|
||||
end
|
||||
|
||||
def to_s
|
||||
finalize_target
|
||||
|
||||
s = @labels.map {|lbl| lbl.name + ":\n" }.join('')
|
||||
s << " #{ADDR_FMT % @pc} "
|
||||
|
||||
case @type
|
||||
when :align
|
||||
s << ('%s %d' % [ @type, @align ])
|
||||
when :nop, :rshift, :add, :sub, :nip,
|
||||
:and, :or, :xor, :swap, :dup
|
||||
s << @type.to_s
|
||||
s << ' return' if @return
|
||||
when :load, :store
|
||||
s << @type.to_s
|
||||
s << ' byte' if @byte_op
|
||||
when :rdrop, :pop, :pushpc, :push, :rdup, :mult, :over, :nlz
|
||||
s << @type.to_s
|
||||
when :immed
|
||||
s << @type.to_s
|
||||
s << (' 0x%-8X' % (@value & 0xffffffff))
|
||||
s << ' # ' << @value.to_s << ' decimal'
|
||||
when :jump, :call
|
||||
s << @type.to_s
|
||||
s << ' ' << @target.name if @target
|
||||
s << ' (' << (ADDR_FMT % @value) << ')' if @value
|
||||
s << ' rel' if @rel
|
||||
s << ' ' << @cc.to_s if @cc
|
||||
s << ' drop' if @drop
|
||||
when :merge
|
||||
s << @type.to_s << (' 0b%07b' % @value)
|
||||
when :resb
|
||||
s << @type.to_s << ' ' << @immed.length.to_s
|
||||
when :byte
|
||||
s << @type.to_s << ' ' << @immed.join(' ')
|
||||
when :word
|
||||
words = @immed.pack('C*').unpack('N*').map { |w| '0x%08x' % w }
|
||||
s << @type.to_s << ' ' << words.join(' ')
|
||||
else
|
||||
raise StandardError.new("Don't know how to output a #{@type} opcode.")
|
||||
end
|
||||
|
||||
s
|
||||
end
|
||||
end
|
||||
|
||||
def parse_options(argv)
|
||||
options = {
|
||||
:include_path => [],
|
||||
:files => []
|
||||
}
|
||||
|
||||
ARGV.each_with_index do |option,idx|
|
||||
case option
|
||||
when /^--origin=(#{POS_INT_REGEX})$/
|
||||
options[:origin] = $1.to_i(0)
|
||||
when /^--format=(binary|hex)$/
|
||||
options[:format] = $1.to_sym
|
||||
options[:pad] = true unless options.has_key? :pad
|
||||
when /^--format=(raw|write|base64)$/
|
||||
options[:format] = $1.to_sym
|
||||
when /^-p|--pad$/
|
||||
options[:pad] = true
|
||||
when /^-r|--no-pad|--raw$/
|
||||
options[:pad] = false
|
||||
when /^--(?:code|disassembly)=(.*)$/
|
||||
options[:code_file] = ($1=='-') ? $stdout : File.open($1, "w")
|
||||
when /^--sym(?:bol)?s=(.*)$/
|
||||
options[:symbol_file] = ($1=='-') ? $stdout : File.open($1, "w")
|
||||
when /^--ram(?:-size)?=(#{POS_INT_REGEX})$/
|
||||
options[:ram_size] = $1.to_i(0)
|
||||
when /^--partial$/
|
||||
options[:code_file] ||= $stdout
|
||||
options[:partial] = true
|
||||
when /^(?:--includes=|-I)(.*)$/
|
||||
options[:include_path] << File.expand_path($1)
|
||||
when /^--depends$/
|
||||
options[:depends_file] = $stdout
|
||||
when /^--$/
|
||||
options[:files] += ARGV[(idx+1) .. -1]
|
||||
break
|
||||
when /^-/
|
||||
raise StandardError.new("Unknown option '#{option}'.")
|
||||
else
|
||||
options[:files] << option
|
||||
end
|
||||
end
|
||||
|
||||
return options
|
||||
end
|
||||
|
||||
$options = {
|
||||
# Defaults
|
||||
:origin => 0x400,
|
||||
:format => :base64,
|
||||
:pad => false,
|
||||
:code_file => nil,
|
||||
:symbol_file => nil,
|
||||
:ram_size => (4 * 2048),
|
||||
:partial => false,
|
||||
:depends_file => false
|
||||
}.merge(parse_options(ARGV)).freeze
|
||||
|
||||
$pc = $options[:origin]
|
||||
$max_pc = $options[:ram_size] - 1
|
||||
|
||||
$instructions = []
|
||||
$accum_labels = []
|
||||
|
||||
OPERAND = /(?:'.'|"(?:[^\\"]|\\"|\\\\)*"|\S+)/
|
||||
ADDR_FMT = "0x%0#{$max_pc.to_s(16).length}x"
|
||||
|
||||
$included_files = []
|
||||
|
||||
def read_asm_file(fname)
|
||||
old_file, old_line, $file, $line = $file, $line, fname, 1
|
||||
|
||||
Label.in_file_scope do
|
||||
File.open(fname).each_line do |ln|
|
||||
ln.sub!(/#.*$/,'')
|
||||
|
||||
ln.split(';').each do |part|
|
||||
while part.sub!(/^\s*(\S+)\s*:\s*/, '')
|
||||
$accum_labels << $1
|
||||
end
|
||||
|
||||
case part
|
||||
when /^\s*$/
|
||||
nil # Empty line or comment
|
||||
|
||||
when /^\s*include\s+"([^"]+)"\s*$/
|
||||
inc_name = $1
|
||||
search_path = [File.dirname(fname)] + $options[:include_path]
|
||||
found = nil
|
||||
|
||||
search_path.each do |dir|
|
||||
try_name = File.expand_path(inc_name, dir)
|
||||
if File.exist? try_name
|
||||
found = try_name
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if found
|
||||
$included_files << found
|
||||
read_asm_file(found)
|
||||
else
|
||||
raise StandardError.new("Unable to locate include file '#{inc_name}'.")
|
||||
end
|
||||
|
||||
when /^\s*export\s+(#{OPERAND}(?:\s*#{OPERAND})*)\s*$/
|
||||
$1.scan(OPERAND).each do |sym|
|
||||
if sym =~ /^\./
|
||||
raise StandardError.new("Can't export local label '#{sym}'.")
|
||||
else
|
||||
lbl = Label.get(sym)
|
||||
lbl.export = true
|
||||
lbl.global = true
|
||||
end
|
||||
end
|
||||
|
||||
when /^\s*import\s+(#{OPERAND}(?:\s*#{OPERAND})*)\s*$/
|
||||
$1.scan(OPERAND).each do |sym|
|
||||
if sym =~ /^\./
|
||||
raise StandardError.new("Can't import local label '#{sym}'.")
|
||||
else
|
||||
Label.get(sym).global = true
|
||||
end
|
||||
end
|
||||
|
||||
when /^\s*(#{OPERAND})\s+eql\s+(#{OPERAND})\s*$/i
|
||||
name, value = $1, $2
|
||||
|
||||
if value =~ /^-?#{POS_INT_REGEX}$/
|
||||
value = value.to_i(0)
|
||||
|
||||
unless $labels[name] and $labels[name].pc == value
|
||||
lbl = Label.define(name)
|
||||
lbl.pc = value
|
||||
lbl.global = !lbl.local?
|
||||
end
|
||||
else
|
||||
lbl = Label.alias(Label.get(value), name)
|
||||
lbl.global = !lbl.local?
|
||||
end
|
||||
|
||||
when /^\s*(\S+)((?:\s+#{OPERAND})*)\s*$/
|
||||
ins = Instruction.new($accum_labels,$pc,$1,$2.scan(/#{OPERAND}/))
|
||||
$accum_labels = []
|
||||
$instructions << ins
|
||||
$pc += ins.bytes
|
||||
end
|
||||
end
|
||||
|
||||
$line += 1
|
||||
end
|
||||
end
|
||||
|
||||
$file, $line = old_file, old_line
|
||||
end
|
||||
|
||||
begin
|
||||
$options[:files].each { |fname| read_asm_file(fname) }
|
||||
rescue => e
|
||||
$stderr.puts "Error at #{$file} line #{$line}:"
|
||||
$stderr.puts e
|
||||
$stderr.puts e.backtrace
|
||||
end
|
||||
|
||||
if $options[:depends_file]
|
||||
$options[:depends_file].puts $included_files
|
||||
exit
|
||||
end
|
||||
|
||||
if $instructions.empty? or not $accum_labels.empty?
|
||||
ins = Instruction.new($accum_labels, $pc, "align", ["1"])
|
||||
$instructions << ins
|
||||
$pc += ins.bytes
|
||||
end
|
||||
|
||||
5.times do
|
||||
$max_pc = $pc
|
||||
$pc = $options[:origin]
|
||||
$layout_changed = false
|
||||
$instructions.each { |ins| ins.reflow($pc); $pc += ins.bytes }
|
||||
break unless $layout_changed
|
||||
end
|
||||
|
||||
if $layout_changed
|
||||
$stderr.puts "WARNING: Opcode layout may be suboptimal."
|
||||
end
|
||||
|
||||
if $options[:code_file]
|
||||
$instructions.each do |ins|
|
||||
$options[:code_file].puts ins
|
||||
end
|
||||
end
|
||||
|
||||
$max_length = $labels.values.inject(0) do |max, lbl|
|
||||
len = lbl.name.length
|
||||
if lbl.export? and (len > max)
|
||||
len
|
||||
else
|
||||
max
|
||||
end
|
||||
end
|
||||
|
||||
if $options[:symbol_file]
|
||||
file = $options[:symbol_file]
|
||||
($labels.values.sort {|a,b| a.pc <=> b.pc }).each do |lbl|
|
||||
if lbl.pc and lbl.export?
|
||||
file.printf "%-*s EQL 0x%08x\n", $max_length, lbl.name, lbl.pc
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
unless $options[:partial]
|
||||
bytes = ($instructions.map { |ins| ins.to_bytes }).flatten
|
||||
|
||||
if $options[:pad] and [ :raw, :binary, :hex ].member? $options[:format]
|
||||
bytes = ([0] * $options[:origin]) + bytes
|
||||
bytes += ([0] * ($options[:ram_size] - bytes.length))
|
||||
end
|
||||
|
||||
file = $stdout
|
||||
|
||||
case $options[:format]
|
||||
when :raw
|
||||
file.write bytes.pack('C*')
|
||||
when :base64
|
||||
file.puts('STORE %X' % $options[:origin])
|
||||
file.print Base64.encode64(bytes.pack('C*'))
|
||||
file.puts '.'
|
||||
($labels.values.sort {|a,b| a.name <=> b.name }).each do |lbl|
|
||||
if lbl.pc and lbl.export?
|
||||
file.printf "# %-*s EQL 0x%08x\n", $max_length, lbl.name, lbl.pc
|
||||
end
|
||||
end
|
||||
when :binary, :hex, :write
|
||||
pc = $options[:origin]
|
||||
bytes = ([0] * (pc & 0x3)) + bytes
|
||||
pc &= ~0x3
|
||||
words = (bytes+[0,0,0]).pack('C*').unpack('N*')
|
||||
addr_len = $max_pc.to_s(16).length
|
||||
words.each do |w|
|
||||
if $options[:format] == :write
|
||||
file.printf "WRITE %08X %0*X\n", w, addr_len, pc
|
||||
elsif $options[:format] == :binary
|
||||
file.printf "%032b\n", w
|
||||
else # hex
|
||||
file.printf "%08X\n", w
|
||||
end
|
||||
|
||||
pc += 4
|
||||
end
|
||||
else
|
||||
raise StandardError.new("Unknown output format")
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
// synthesis attribute slice_utilization_ratio of StackCPU is 50;
|
||||
module StackCPU (CLK_I, RST_I, IRQ_I, IACK_O, IADR_I,
|
||||
INST_ADR_O, INST_DAT_I, INST_CYC_O, INST_STB_O, INST_ACK_I,
|
||||
DATA_ADR_O, DATA_DAT_I, DATA_DAT_O, DATA_CYC_O, DATA_STB_O, DATA_WE_O,
|
||||
DATA_SEL_O, DATA_ACK_I);
|
||||
|
||||
input CLK_I;
|
||||
input RST_I;
|
||||
|
||||
input IRQ_I;
|
||||
output IACK_O;
|
||||
input [31:0] IADR_I;
|
||||
|
||||
output [31:0] INST_ADR_O;
|
||||
input [7:0] INST_DAT_I;
|
||||
output INST_CYC_O;
|
||||
output INST_STB_O;
|
||||
input INST_ACK_I;
|
||||
|
||||
output [31:2] DATA_ADR_O;
|
||||
input [31:0] DATA_DAT_I;
|
||||
output [31:0] DATA_DAT_O;
|
||||
output DATA_CYC_O;
|
||||
output DATA_STB_O;
|
||||
output DATA_WE_O;
|
||||
output [3:0] DATA_SEL_O;
|
||||
input DATA_ACK_I;
|
||||
|
||||
reg [31:0] PC = 32'd0; /* address of current instr. */
|
||||
reg [31:0] T = 32'd0; /* Top of (data) stack */
|
||||
reg [31:0] N = 32'd0; /* Next of (data) stack */
|
||||
reg [31:0] R = 32'd0; /* top of Return stack */
|
||||
reg [8:0] SP = 9'd0; /* Stack Pointer */
|
||||
reg [8:0] RP = 9'd0; /* Return stack Pointer */
|
||||
|
||||
wire [31:0] INST_ADR_O = PC;
|
||||
reg INST_CYC_O = 1'b1;
|
||||
reg INST_STB_O = 1'b1;
|
||||
|
||||
wire [31:2] DATA_ADR_O = T[31:2];
|
||||
reg [31:0] DATA_DAT_O;
|
||||
reg DATA_CYC_O = 1'b0;
|
||||
reg DATA_STB_O = 1'b0;
|
||||
reg DATA_WE_O = 1'b0;
|
||||
reg [3:0] DATA_SEL_O = 4'b0000;
|
||||
|
||||
wire [31:0] STACK_M1_OUT;
|
||||
wire [31:0] STACK_M2_OUT;
|
||||
wire [31:0] RETURN_OUT;
|
||||
|
||||
wire CMP_EQ = ~|N;
|
||||
wire CMP_LT = N[31];
|
||||
wire CMP_GT = ~(CMP_EQ|CMP_LT);
|
||||
reg CMP_TRUE;
|
||||
|
||||
StackRAM DataStack1 (
|
||||
.CLKIN(CLK_I),
|
||||
.ADDR_A(SP),
|
||||
.WE_A(1'b1),
|
||||
.IN_A(N),
|
||||
.ADDR_B(SP - 9'd1),
|
||||
.OUT_B(STACK_M1_OUT)
|
||||
);
|
||||
|
||||
StackRAM DataStack2 (
|
||||
.CLKIN(CLK_I),
|
||||
.ADDR_A(SP),
|
||||
.WE_A(1'b1),
|
||||
.IN_A(N),
|
||||
.ADDR_B(SP - 9'd2),
|
||||
.OUT_B(STACK_M2_OUT)
|
||||
);
|
||||
|
||||
StackRAM ReturnStack (
|
||||
.CLKIN(CLK_I),
|
||||
.ADDR_A(RP),
|
||||
.WE_A(1'b1),
|
||||
.IN_A(R),
|
||||
.ADDR_B(RP - 9'd1),
|
||||
.OUT_B(RETURN_OUT)
|
||||
);
|
||||
|
||||
wire [5:0] NLZ_OUT;
|
||||
|
||||
NLZ NLZ_inst (
|
||||
.IN(T),
|
||||
.OUT(NLZ_OUT)
|
||||
);
|
||||
|
||||
reg DO_IRQ = 1'b0;
|
||||
wire IACK_O = IRQ_I & DO_IRQ;
|
||||
|
||||
reg USE_SAVED_IR = 1'b0;
|
||||
reg [7:0] SAVED_IR;
|
||||
|
||||
wire [7:0] IR = USE_SAVED_IR ? SAVED_IR : INST_DAT_I;
|
||||
wire IR_AVAIL = (USE_SAVED_IR | INST_ACK_I) & ~DO_IRQ;
|
||||
|
||||
wire IS_DATA = (IR[7:2] == 6'b000110);
|
||||
reg USE_SAVED_DATA = 1'b0;
|
||||
reg [31:0] SAVED_DATA;
|
||||
|
||||
wire [31:0] DATA_IN = USE_SAVED_DATA ? SAVED_DATA : DATA_DAT_I;
|
||||
wire DATA_ACKED = (USE_SAVED_DATA | DATA_ACK_I);
|
||||
|
||||
reg [7:0] BYTE_IN;
|
||||
|
||||
always @*
|
||||
begin
|
||||
casex (IR[3:1])
|
||||
3'b000: /* never */ CMP_TRUE <= 1'b0;
|
||||
3'b001: /* equal */ CMP_TRUE <= CMP_EQ;
|
||||
3'b010: /* less */ CMP_TRUE <= CMP_LT;
|
||||
3'b011: /* greater */ CMP_TRUE <= CMP_GT;
|
||||
3'b100: /* always */ CMP_TRUE <= 1'b1;
|
||||
3'b101: /* !equal */ CMP_TRUE <= !CMP_EQ;
|
||||
3'b110: /* !less */ CMP_TRUE <= !CMP_LT;
|
||||
3'b111: /* !greater */ CMP_TRUE <= !CMP_GT;
|
||||
endcase
|
||||
|
||||
DATA_CYC_O <= IR_AVAIL & IS_DATA & ~USE_SAVED_DATA;
|
||||
DATA_STB_O <= IR_AVAIL & IS_DATA & ~USE_SAVED_DATA;
|
||||
DATA_WE_O <= IR[1]; /* 1 if STORE */
|
||||
|
||||
casex ({IR[0], T[1:0]})
|
||||
3'b0XX: DATA_SEL_O <= 4'b1111;
|
||||
3'b100: DATA_SEL_O <= 4'b1000;
|
||||
3'b101: DATA_SEL_O <= 4'b0100;
|
||||
3'b110: DATA_SEL_O <= 4'b0010;
|
||||
3'b111: DATA_SEL_O <= 4'b0001;
|
||||
endcase
|
||||
|
||||
casex ({IR[0], T[1:0]})
|
||||
3'b0XX: DATA_DAT_O <= N;
|
||||
3'b100: DATA_DAT_O <= { N[7:0], 24'h000000 };
|
||||
3'b101: DATA_DAT_O <= { 8'h00, N[7:0], 16'h0000 };
|
||||
3'b110: DATA_DAT_O <= { 16'h0000, N[7:0], 8'h00 };
|
||||
3'b111: DATA_DAT_O <= { 24'h000000, N[7:0] };
|
||||
endcase
|
||||
|
||||
casex (T[1:0])
|
||||
2'b00: BYTE_IN <= DATA_IN[31:24];
|
||||
2'b01: BYTE_IN <= DATA_IN[23:16];
|
||||
2'b10: BYTE_IN <= DATA_IN[15: 8];
|
||||
2'b11: BYTE_IN <= DATA_IN[ 7: 0];
|
||||
endcase
|
||||
end
|
||||
|
||||
wire IS_MULT = (IR == 8'b00010111);
|
||||
reg [63:0] MULT_OUT;
|
||||
reg MULT_READY = 1'b0;
|
||||
|
||||
wire DATA_WAIT = IS_DATA & ~DATA_ACKED;
|
||||
wire MULT_WAIT = IS_MULT & ~MULT_READY;
|
||||
wire OPCODE_COMPLETE = IR_AVAIL & ~DATA_WAIT & ~MULT_WAIT;
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
MULT_OUT <= $unsigned(N) * $unsigned(T);
|
||||
|
||||
if (RST_I)
|
||||
begin
|
||||
PC <= 32'd0;
|
||||
SP <= 9'd0;
|
||||
RP <= 9'd0;
|
||||
T <= 32'd0;
|
||||
N <= 32'd0;
|
||||
R <= 32'd0;
|
||||
USE_SAVED_IR <= 1'b0;
|
||||
USE_SAVED_DATA <= 1'b0;
|
||||
INST_CYC_O <= 1'b0;
|
||||
INST_STB_O <= 1'b0;
|
||||
MULT_READY <= 1'b0;
|
||||
DO_IRQ <= 1'b0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (DO_IRQ)
|
||||
begin
|
||||
// Simulate a call to the address in IADR_I
|
||||
USE_SAVED_IR <= 1'b0;
|
||||
USE_SAVED_DATA <= 1'b0;
|
||||
INST_CYC_O <= 1'b1;
|
||||
INST_STB_O <= 1'b1;
|
||||
MULT_READY <= 1'b0;
|
||||
DO_IRQ <= 1'b0;
|
||||
|
||||
SP <= SP;
|
||||
RP <= RP+1;
|
||||
T <= T;
|
||||
N <= N;
|
||||
R <= PC;
|
||||
PC <= IADR_I;
|
||||
end
|
||||
else if (OPCODE_COMPLETE)
|
||||
begin
|
||||
USE_SAVED_IR <= 1'b0;
|
||||
USE_SAVED_DATA <= 1'b0;
|
||||
INST_CYC_O <= ~IRQ_I;
|
||||
INST_STB_O <= ~IRQ_I;
|
||||
MULT_READY <= 1'b0;
|
||||
DO_IRQ <= IRQ_I;
|
||||
|
||||
casex (IR)
|
||||
8'b0000001X: /* RSHIFT */ SP <= SP-1;
|
||||
8'b000001XX: /* ADD/SUB */ SP <= SP-1;
|
||||
8'b00001XXX: /* LOGIC */ SP <= SP-1;
|
||||
8'b0001001X: /* DUP */ SP <= SP+1;
|
||||
8'b00010100: /* OVER */ SP <= SP+1;
|
||||
8'b0001101X: /* STORE */ SP <= SP-2;
|
||||
8'b00011101: /* POP */ SP <= SP+1;
|
||||
8'b00011111: /* PUSH */ SP <= SP-1;
|
||||
8'b001XXXXX: /* IMMED */ SP <= SP+1;
|
||||
8'b01XXXXX0: /* JUMP/CALL */ SP <= SP-1;
|
||||
8'b01XXXXX1: /* J/C DROP */ SP <= SP-2;
|
||||
8'bXXXXXXXX: /* other */ SP <= SP;
|
||||
endcase
|
||||
|
||||
casex (IR)
|
||||
8'b00010101: /* RDUP */ RP <= RP+1;
|
||||
8'b00010111: /* MULT */ RP <= RP;
|
||||
8'b00011001: /* LOAD BYTE */ RP <= RP;
|
||||
8'b00011011: /* STORE BYTE */ RP <= RP;
|
||||
8'b00011100: /* RDROP */ RP <= RP-1;
|
||||
8'b00011101: /* POP */ RP <= RP-1;
|
||||
8'b00011110: /* PUSHPC */ RP <= RP+1;
|
||||
8'b00011111: /* PUSH */ RP <= RP+1;
|
||||
8'b001XXXXX: /* IMMED */ RP <= RP;
|
||||
8'b010XXXXX: /* JUMP */ RP <= RP;
|
||||
8'b011XXXXX: /* CALL */ RP <= CMP_TRUE ? (RP+1) : RP;
|
||||
8'b1XXXXXXX: /* MERGE */ RP <= RP;
|
||||
8'bXXXXXXX1: /* RETURN */ RP <= RP-1;
|
||||
8'bXXXXXXXX: /* other */ RP <= RP;
|
||||
endcase
|
||||
|
||||
casex (IR)
|
||||
8'b0000000X: /* NOP */ T <= T;
|
||||
8'b0000001X: /* RSHIFT */ T <= T[31] ? (N << (-T[5:0]))
|
||||
: (N >> T[5:0]);
|
||||
8'b0000010X: /* ADD */ T <= N + T;
|
||||
8'b0000011X: /* SUB */ T <= N - T;
|
||||
8'b0000100X: /* NIP */ T <= T;
|
||||
8'b0000101X: /* AND */ T <= N & T;
|
||||
8'b0000110X: /* OR */ T <= N | T;
|
||||
8'b0000111X: /* XOR */ T <= N ^ T;
|
||||
8'b0001000X: /* SWAP */ T <= N;
|
||||
8'b0001001X: /* DUP */ T <= T;
|
||||
8'b00010100: /* OVER */ T <= N;
|
||||
8'b00010101: /* RDUP */ T <= T;
|
||||
8'b00010110: /* NLZ */ T <= NLZ_OUT;
|
||||
8'b00010111: /* MULT */ T <= MULT_OUT[63:32];
|
||||
8'b00011000: /* LOAD */ T <= DATA_IN;
|
||||
8'b00011001: /* LOAD BYTE */ T <= BYTE_IN;
|
||||
8'b0001101X: /* STORE */ T <= STACK_M1_OUT;
|
||||
8'b00011100: /* RDROP */ T <= T;
|
||||
8'b00011101: /* POP */ T <= R;
|
||||
8'b00011110: /* PUSHPC */ T <= T;
|
||||
8'b00011111: /* PUSH */ T <= N;
|
||||
8'b001XXXXX: /* IMMED */ T <= $signed(IR[4:0]);
|
||||
8'b01XXXXX0: /* JUMP/CALL */ T <= N;
|
||||
8'b01XXXXX1: /* J/C DROP */ T <= STACK_M1_OUT;
|
||||
8'b1XXXXXXX: /* MERGE */ T <= (T<<7) | IR[6:0];
|
||||
endcase
|
||||
|
||||
casex (IR)
|
||||
8'b0000000X: /* NOP */ N <= N;
|
||||
8'b0000001X: /* RSHIFT */ N <= STACK_M1_OUT;
|
||||
8'b0000010X: /* ADD */ N <= STACK_M1_OUT;
|
||||
8'b0000011X: /* SUB */ N <= STACK_M1_OUT;
|
||||
8'b0000100X: /* NIP */ N <= STACK_M1_OUT;
|
||||
8'b0000101X: /* AND */ N <= STACK_M1_OUT;
|
||||
8'b0000110X: /* OR */ N <= STACK_M1_OUT;
|
||||
8'b0000111X: /* XOR */ N <= STACK_M1_OUT;
|
||||
8'b0001000X: /* SWAP */ N <= T;
|
||||
8'b0001001X: /* DUP */ N <= T;
|
||||
8'b00010100: /* OVER */ N <= T;
|
||||
8'b00010101: /* RDUP */ N <= N;
|
||||
8'b00010110: /* NLZ */ N <= N;
|
||||
8'b00010111: /* MULT */ N <= MULT_OUT[31:0];
|
||||
8'b0001100X: /* LOAD */ N <= N;
|
||||
8'b0001101X: /* STORE */ N <= STACK_M2_OUT;
|
||||
8'b00011100: /* RDROP */ N <= N;
|
||||
8'b00011101: /* POP */ N <= T;
|
||||
8'b00011110: /* PUSHPC */ N <= N;
|
||||
8'b00011111: /* PUSH */ N <= STACK_M1_OUT;
|
||||
8'b001XXXXX: /* IMMED */ N <= T;
|
||||
8'b01XXXXX0: /* JUMP/CALL */ N <= STACK_M1_OUT;
|
||||
8'b01XXXXX1: /* J/C DROP */ N <= STACK_M2_OUT;
|
||||
8'b1XXXXXXX: /* MERGE */ N <= N;
|
||||
endcase
|
||||
|
||||
casex (IR)
|
||||
8'b00010101: /* RDUP */ R <= R;
|
||||
8'b00010111: /* MULT */ R <= R;
|
||||
8'b00011001: /* LOAD BYTE */ R <= R;
|
||||
8'b00011011: /* STORE BYTE */ R <= R;
|
||||
8'b00011100: /* RDROP */ R <= RETURN_OUT;
|
||||
8'b00011101: /* POP */ R <= RETURN_OUT;
|
||||
8'b00011110: /* PUSHPC */ R <= PC+1;
|
||||
8'b00011111: /* PUSH */ R <= T;
|
||||
8'b001XXXXX: /* IMMED */ R <= R;
|
||||
8'b010XXXXX: /* JUMP */ R <= R;
|
||||
8'b011XXXXX: /* CALL */ R <= CMP_TRUE ? (PC+1) : R;
|
||||
8'b1XXXXXXX: /* MERGE */ R <= R;
|
||||
8'bXXXXXXX1: /* RETURN */ R <= RETURN_OUT;
|
||||
8'bXXXXXXXX: /* other */ R <= R;
|
||||
endcase
|
||||
|
||||
casex (IR)
|
||||
8'b00010101: /* RDUP */ PC <= PC + 1;
|
||||
8'b00010111: /* MULT */ PC <= PC + 1;
|
||||
8'b00011001: /* LOAD BYTE */ PC <= PC + 1;
|
||||
8'b00011011: /* STORE BYTE */ PC <= PC + 1;
|
||||
8'b00011101: /* POP */ PC <= PC + 1;
|
||||
8'b00011111: /* PUSH */ PC <= PC + 1;
|
||||
8'b001XXXXX: /* IMMED */ PC <= PC + 1;
|
||||
8'b01X0XXXX: /* JUMP/CALL */ PC <= CMP_TRUE ? T : (PC+1);
|
||||
8'b01X1XXXX: /* " REL */ PC <= CMP_TRUE ? ((PC+1)+T) : (PC+1);
|
||||
8'b1XXXXXXX: /* MERGE */ PC <= PC + 1;
|
||||
8'bXXXXXXX1: /* RETURN */ PC <= R;
|
||||
8'bXXXXXXXX: /* other */ PC <= PC + 1;
|
||||
endcase
|
||||
end
|
||||
else
|
||||
begin
|
||||
INST_CYC_O <= ~IR_AVAIL;
|
||||
INST_STB_O <= ~IR_AVAIL;
|
||||
|
||||
if (INST_ACK_I)
|
||||
begin
|
||||
SAVED_IR <= INST_DAT_I;
|
||||
USE_SAVED_IR <= 1'b1;
|
||||
end
|
||||
|
||||
if (DATA_ACK_I)
|
||||
begin
|
||||
SAVED_DATA <= DATA_DAT_I;
|
||||
USE_SAVED_DATA <= 1'b1;
|
||||
end
|
||||
|
||||
MULT_READY <= 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
// vim:set sw=3:
|
||||
// Source modes: Destination modes:
|
||||
// constant data discard
|
||||
// constant address constant address
|
||||
// decrementing address decrementing address
|
||||
// incrementing address incrementing address
|
||||
|
||||
// Constant source data is for initialization (e.g. zero-fill).
|
||||
// Discard destination is for computations (e.g. CRC [future]).
|
||||
// All transfers are word-aligned -- no SEL_O signals are generated.
|
||||
|
||||
// Control interface:
|
||||
// 0x00 source address (R/W)
|
||||
// 0x04 dest. address (R/W)
|
||||
// 0x08 status/control (RO)
|
||||
|
||||
// IRQ_O is edge-triggered, active-high. 0->1 indicates completion.
|
||||
|
||||
// synthesis attribute slice_utilization_ratio of WB_DMA is 15;
|
||||
module WB_DMA (CLK_I, RST_I, IRQ_O,
|
||||
CTL_ADR_I, CTL_DAT_I, CTL_DAT_O, CTL_STB_I, CTL_WE_I, CTL_ACK_O,
|
||||
SRC_ADR_O, SRC_DAT_I, SRC_STB_O, SRC_WE_O, SRC_ACK_I,
|
||||
DST_ADR_O, DST_DAT_O, DST_STB_O, DST_WE_O, DST_ACK_I);
|
||||
|
||||
parameter ADDR_WIDTH = 30;
|
||||
parameter DATA_WIDTH = 32;
|
||||
|
||||
input CLK_I, RST_I;
|
||||
output IRQ_O;
|
||||
|
||||
input CTL_STB_I, CTL_WE_I;
|
||||
input [1:0] CTL_ADR_I;
|
||||
input [31:0] CTL_DAT_I;
|
||||
output [31:0] CTL_DAT_O;
|
||||
output CTL_ACK_O;
|
||||
|
||||
output [ADDR_WIDTH-1:0] SRC_ADR_O;
|
||||
input [DATA_WIDTH-1:0] SRC_DAT_I;
|
||||
output SRC_STB_O, SRC_WE_O;
|
||||
input SRC_ACK_I;
|
||||
|
||||
output [ADDR_WIDTH-1:0] DST_ADR_O;
|
||||
output [DATA_WIDTH-1:0] DST_DAT_O;
|
||||
output DST_STB_O, DST_WE_O;
|
||||
input DST_ACK_I;
|
||||
|
||||
reg [DATA_WIDTH-1:0] SRC_ADR_REG;
|
||||
reg [DATA_WIDTH-1:0] DST_ADR_REG;
|
||||
reg [1:0] SRC_TYPE, DST_TYPE;
|
||||
reg [16:0] WORD_COUNT = 0;
|
||||
|
||||
wire CMD_WRITE = CTL_STB_I & CTL_WE_I & (CTL_ADR_I == 2'h2);
|
||||
|
||||
wire CONSTANT = ~|SRC_TYPE;
|
||||
wire DISCARD = ~|DST_TYPE;
|
||||
wire CANCEL = CMD_WRITE & CTL_DAT_I[1];
|
||||
wire START = CMD_WRITE & CTL_DAT_I[0];
|
||||
wire RUNNING = |WORD_COUNT & ~RST_I;
|
||||
wire DONE;
|
||||
|
||||
FIFO #(
|
||||
.QUEUE_SIZE(2),
|
||||
.DATA_WIDTH(32)
|
||||
) TransferFIFO (
|
||||
.CLK_I(CLK_I),
|
||||
.RST_I(RST_I | CANCEL),
|
||||
.DAT_I(CONSTANT ? SRC_ADR_REG : SRC_DAT_I),
|
||||
.DAT_O(DST_DAT_O),
|
||||
.QUEUE_I(QUEUE),
|
||||
.DEQUEUE_I(DEQUEUE),
|
||||
.EMPTY_O(FIFO_EMPTY),
|
||||
.FULL_O(FIFO_FULL)
|
||||
);
|
||||
|
||||
assign QUEUE = CONSTANT ? (RUNNING & ~FIFO_FULL) : (SRC_STB_O & SRC_ACK_I);
|
||||
assign DEQUEUE = DISCARD ? ~FIFO_EMPTY : (DST_STB_O & DST_ACK_I);
|
||||
assign DONE = ~RUNNING & FIFO_EMPTY;
|
||||
assign IRQ_O = DONE;
|
||||
|
||||
assign SRC_ADR_O = SRC_ADR_REG[DATA_WIDTH-1:DATA_WIDTH-ADDR_WIDTH];
|
||||
assign DST_ADR_O = DST_ADR_REG[DATA_WIDTH-1:DATA_WIDTH-ADDR_WIDTH];
|
||||
|
||||
assign SRC_STB_O = RUNNING & ~CONSTANT & ~FIFO_FULL;
|
||||
assign DST_STB_O = ~DISCARD & ~FIFO_EMPTY & ~RST_I;
|
||||
|
||||
assign SRC_WE_O = 1'b0;
|
||||
assign DST_WE_O = 1'b1;
|
||||
|
||||
assign CTL_ACK_O = CTL_STB_I;
|
||||
|
||||
reg [31:0] CTL_DAT_O;
|
||||
|
||||
wire [31:0] STATUS = {
|
||||
WORD_COUNT[15:0],
|
||||
4'h0,
|
||||
{ 2'b0, SRC_TYPE },
|
||||
{ 2'b0, DST_TYPE },
|
||||
{ 3'b0, ~DONE }
|
||||
};
|
||||
|
||||
always @*
|
||||
begin
|
||||
case (CTL_ADR_I)
|
||||
2'h0: CTL_DAT_O <= SRC_ADR_REG;
|
||||
2'h1: CTL_DAT_O <= DST_ADR_REG;
|
||||
2'h2: CTL_DAT_O <= STATUS;
|
||||
2'h3: CTL_DAT_O <= 32'dX;
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (RST_I | CANCEL)
|
||||
begin
|
||||
WORD_COUNT <= 0;
|
||||
end
|
||||
else if (DONE)
|
||||
begin
|
||||
if (CTL_STB_I & CTL_WE_I)
|
||||
begin
|
||||
case (CTL_ADR_I)
|
||||
2'h0: SRC_ADR_REG <= CTL_DAT_I;
|
||||
2'h1: DST_ADR_REG <= CTL_DAT_I;
|
||||
endcase
|
||||
end
|
||||
|
||||
if (START)
|
||||
begin
|
||||
// word count of zero means 2^16 == 0x10000 words.
|
||||
WORD_COUNT <= { ~|CTL_DAT_I[31:16], CTL_DAT_I[31:16] };
|
||||
SRC_TYPE <= CTL_DAT_I[9:8];
|
||||
DST_TYPE <= CTL_DAT_I[5:4];
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (QUEUE)
|
||||
begin
|
||||
WORD_COUNT <= WORD_COUNT - 1;
|
||||
|
||||
case (SRC_TYPE)
|
||||
2'b00: SRC_ADR_REG <= SRC_ADR_REG;
|
||||
2'b01: SRC_ADR_REG <= SRC_ADR_REG;
|
||||
2'b10: SRC_ADR_REG <= SRC_ADR_REG - (DATA_WIDTH/8);
|
||||
2'b11: SRC_ADR_REG <= SRC_ADR_REG + (DATA_WIDTH/8);
|
||||
endcase
|
||||
end
|
||||
|
||||
if (DEQUEUE)
|
||||
begin
|
||||
case (DST_TYPE)
|
||||
2'b00: DST_ADR_REG <= DST_ADR_REG;
|
||||
2'b01: DST_ADR_REG <= DST_ADR_REG;
|
||||
2'b10: DST_ADR_REG <= DST_ADR_REG - (DATA_WIDTH/8);
|
||||
2'b11: DST_ADR_REG <= DST_ADR_REG + (DATA_WIDTH/8);
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
NOP rtn:1 ( -- )
|
||||
RSHIFT rtn:1 ( a b -- (a>>b) )
|
||||
ADD rtn:1 ( a b -- (a+b) )
|
||||
SUB rtn:1 ( a b -- (a-b) )
|
||||
NIP rtn:1 ( a b -- b )
|
||||
AND rtn:1 ( a b -- (a&b) )
|
||||
OR rtn:1 ( a b -- (a|b) )
|
||||
XOR rtn:1 ( a b -- (a^b) )
|
||||
SWAP rtn:1 ( a b -- b a )
|
||||
DUP rtn:1 ( a -- a a )
|
||||
OVER ( a b -- a b a )
|
||||
RDUP ( -- ) R( ra -- ra ra )
|
||||
NLZ ( a -- nlz(a) )
|
||||
MULT ( a b -- msw lsw )
|
||||
LOAD byte:1 ( a -- mem[a] )
|
||||
STORE byte:1 ( a b -- )
|
||||
RDROP ( -- ) R( a -- )
|
||||
POP ( -- a ) R( a -- )
|
||||
PUSHPC ( -- ) R( -- pc )
|
||||
PUSH ( a -- ) R( -- a )
|
||||
IMMED data:5 ( -- extend(data) )
|
||||
JUMP rel:1 cc:3 drop:1 ( c a -- c? )
|
||||
CALL rel:1 cc:3 drop:1 ( c a -- c? ) R( -- pc )
|
||||
MERGE data:7 ( a -- ((a<<7)|data) )
|
||||
|
||||
cc=000: never (drop/drop2)
|
||||
cc=001: ST0 == 0
|
||||
cc=010: ST0 < 0
|
||||
cc=011: ST0 > 0
|
||||
cc=100: always
|
||||
cc=101: ST0 != 0
|
||||
cc=110: ST0 >= 0
|
||||
cc=111: ST0 <= 0
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
opcode | mnem. | SP | RP | T | N | R | PC |cycles
|
||||
---------|-----------|------|--------|-------|--------|--------|--------|------
|
||||
0000000X | NOP | SP | RETURN | T | N | RETURN | RETURN | 1
|
||||
0000001X | RSHIFT | SP-1 | RETURN | expr. | [SP-1] | RETURN | RETURN | 1
|
||||
0000010X | ADD | SP-1 | RETURN | expr. | [SP-1] | RETURN | RETURN | 1
|
||||
0000011X | SUB | SP-1 | RETURN | expr. | [SP-1] | RETURN | RETURN | 1
|
||||
00001XXX | LOGIC | SP-1 | RETURN | expr. | [SP-1] | RETURN | RETURN | 1
|
||||
0001000X | SWAP | SP | RETURN | N | T | RETURN | RETURN | 1
|
||||
0001001X | DUP | SP+1 | RETURN | T | T | RETURN | RETURN | 1
|
||||
00010100 | OVER | SP+1 | RP | N | T | R | PC+1 | 1
|
||||
00010101 | RDUP | SP | RP+1 | T | N | R | PC+1 | 1
|
||||
00010110 | NLZ | SP | RP | expr. | N | R | PC+1 | 1
|
||||
00010111 | MULT | SP | RP | expr. | expr. | R | PC+1 | 2
|
||||
0001100X | LOAD | SP | RP | expr. | N | R | PC+1 | 1*
|
||||
0001101X | STORE | SP-2 | RP | expr. | [SP-2] | R | PC+1 | 1*
|
||||
00011100 | RDROP | SP | RP-1 | T | N | [RP-1] | PC+1 | 1
|
||||
00011101 | POP | SP+1 | RP-1 | R | T | [RP-1] | PC+1 | 1
|
||||
00011110 | PUSHPC | SP | RP+1 | T | N | PC+1 | PC+1 | 1
|
||||
00011111 | PUSH | SP-1 | RP+1 | N | [SP-1] | T | PC+1 | 1
|
||||
001XXXXX | IMMED | SP+1 | RP | expr. | T | R | PC+1 | 1
|
||||
010XXXX0 | JUMP | SP-1 | RP | N | [SP-1] | R | TARGET | 1*
|
||||
010XXXX1 | JUMP DROP | SP-2 | RP | expr. | [SP-2] | R | TARGET | 1*
|
||||
011XXXX0 | CALL | SP-1 | CALL | N | [SP-1] | CALL | TARGET | 1*
|
||||
011XXXX1 | CALL DROP | SP-2 | CALL | expr. | [SP-2] | CALL | TARGET | 1*
|
||||
1XXXXXXX | MERGE | SP | RP | expr. | N | R | PC+1 | 1
|
||||
|
||||
RP:RETURN = opcode[0] ? (RP-1) : RP
|
||||
R:RETURN = opcode[0] ? [RP-1] : R
|
||||
PC:RETURN = opcode[0] ? R : (PC+1)
|
||||
RP:CALL = cond(N) ? (RP+1) : RP
|
||||
R:CALL = cond(N) ? (PC+1) : R
|
||||
PC:TARGET = cond(N) ? (rel ? (PC+1+T) : T) : (PC+1)
|
||||
|
||||
(*) External device can insert additional wait states.
|
||||
|
||||
opcode | T:expr. | N:expr. |
|
||||
-------|---------|----------|
|
||||
RSHIFT | N >> T | --- |
|
||||
ADD | N + T | --- |
|
||||
SUB | N - T | --- |
|
||||
NIP | T | --- |
|
||||
AND | N & T | --- |
|
||||
OR | N | T | --- |
|
||||
XOR | N ^ T | --- |
|
||||
NLZ | nlz(T) | --- |
|
||||
MULT | msw <- N*T -> lsw |
|
||||
LOAD | data in | --- |
|
||||
STORE | [SP-1] | --- |
|
||||
IMMED | immed | --- |
|
||||
J DROP | [SP-1] | --- |
|
||||
C DROP | [SP-1] | --- |
|
||||
MERGE | T:merge | --- |
|
||||
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
module FIFO (CLK_I, RST_I, DAT_I, DAT_O, QUEUE_I, DEQUEUE_I, EMPTY_O, FULL_O);
|
||||
|
||||
// entries = 2**QUEUE_SIZE
|
||||
parameter QUEUE_SIZE = 2;
|
||||
parameter DATA_WIDTH = 32;
|
||||
|
||||
// If true, queue and dequeue can be simultaneous
|
||||
// on empty and full queues. Otherwise data must
|
||||
// pass through the queue first, costing one cycle.
|
||||
parameter WRITE_THROUGH = 0;
|
||||
|
||||
input CLK_I, RST_I, QUEUE_I, DEQUEUE_I;
|
||||
input [DATA_WIDTH-1:0] DAT_I;
|
||||
output [DATA_WIDTH-1:0] DAT_O;
|
||||
output EMPTY_O, FULL_O;
|
||||
|
||||
reg [QUEUE_SIZE-1:0] HEAD = 0;
|
||||
reg [QUEUE_SIZE-1:0] TAIL = 0;
|
||||
|
||||
wire [QUEUE_SIZE-1:0] NEXT_HEAD = HEAD + 1;
|
||||
|
||||
generate
|
||||
if (WRITE_THROUGH == 0)
|
||||
begin : force_queue
|
||||
assign EMPTY_O = (HEAD == TAIL);
|
||||
assign FULL_O = (NEXT_HEAD == TAIL);
|
||||
end
|
||||
else
|
||||
begin : write_through
|
||||
assign EMPTY_O = (HEAD == TAIL) & ~QUEUE_I;
|
||||
assign FULL_O = (NEXT_HEAD == TAIL) & ~DEQUEUE_I;
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (RST_I)
|
||||
begin
|
||||
HEAD <= 0;
|
||||
TAIL <= 0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (QUEUE_I & ~FULL_O)
|
||||
HEAD <= HEAD + 1;
|
||||
|
||||
if (DEQUEUE_I & ~EMPTY_O)
|
||||
TAIL <= TAIL + 1;
|
||||
end
|
||||
end
|
||||
|
||||
// synthesis attribute ram_style of QUEUE is distributed;
|
||||
reg [DATA_WIDTH-1:0] QUEUE[0:(1<<QUEUE_SIZE)-1];
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (QUEUE_I & ~FULL_O)
|
||||
QUEUE[HEAD] <= DAT_I;
|
||||
end
|
||||
|
||||
generate
|
||||
if (WRITE_THROUGH == 0)
|
||||
begin : force_queue_out
|
||||
assign DAT_O = QUEUE[TAIL];
|
||||
end
|
||||
else
|
||||
begin : write_through_out
|
||||
assign DAT_O = (HEAD == TAIL) ? DAT_I : QUEUE[TAIL];
|
||||
end
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
// synthesis attribute slice_utilization_ratio of IRQ_CTL is 7;
|
||||
module IRQ_CTL (CLK_I, RST_I, IRQ_O, IADR_O, IACK_I,
|
||||
ADR_I, DAT_I, DAT_O, STB_I, WE_I, SEL_I, ACK_O,
|
||||
IRQ7, IRQ6, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0);
|
||||
|
||||
// Address layout (bytes):
|
||||
// 0x00..0x03 IADR0
|
||||
// 0x04..0x07 IADR1
|
||||
// 0x08..0x0B IADR2
|
||||
// 0x0C..0x0F IADR3
|
||||
// 0x10..0x13 IADR4
|
||||
// 0x14..0x17 IADR5
|
||||
// 0x18..0x1B IADR6
|
||||
// 0x1C..0x1F IADR7
|
||||
// 0x20 polarity[irq7..irq0]
|
||||
// 0x21 trigger[irq7..irq0]
|
||||
// 0x22 mask[irq7..irq0]
|
||||
// 0x23 status[irq7..irq0]
|
||||
// 0x24..0x3F reserved (0)
|
||||
|
||||
// Triggers
|
||||
`define TR_LEVEL 1'b0
|
||||
`define TR_EDGE 1'b1
|
||||
|
||||
// Polarities
|
||||
`define PL_LOW 1'b0
|
||||
`define PL_HIGH 1'b1
|
||||
`define PE_FALLING 1'b0
|
||||
`define PE_RISING 1'b1
|
||||
|
||||
input CLK_I, RST_I, IACK_I, STB_I, WE_I;
|
||||
output IRQ_O, ACK_O;
|
||||
output [31:0] IADR_O;
|
||||
input [3:0] ADR_I;
|
||||
input [31:0] DAT_I;
|
||||
output [31:0] DAT_O;
|
||||
input [3:0] SEL_I;
|
||||
input IRQ7, IRQ6, IRQ5, IRQ4;
|
||||
input IRQ3, IRQ2, IRQ1, IRQ0;
|
||||
|
||||
// synthesis attribute ram_style of IADR is distributed;
|
||||
reg [31:0] IADR[0:7];
|
||||
|
||||
reg [7:0] TRIGGER = 8'h00;
|
||||
reg [7:0] POLARITY = 8'hFF;
|
||||
reg [7:0] MASK = 8'h00;
|
||||
reg [7:0] STATUS = 8'h00;
|
||||
|
||||
reg [7:0] PREV_IRQS = 8'h00;
|
||||
reg [7:0] DELIVERED = 8'h00;
|
||||
wire [7:0] PRIO_MASK = ~( DELIVERED | (DELIVERED<<1) | (DELIVERED<<2) | (DELIVERED<<3) |
|
||||
(DELIVERED<<4) | (DELIVERED<<5) | (DELIVERED<<6) | (DELIVERED<<7) );
|
||||
wire [7:0] IRQS = { IRQ7, IRQ6, IRQ5, IRQ4, IRQ3, IRQ2, IRQ1, IRQ0 };
|
||||
wire [7:0] MASKED_IRQS = STATUS & MASK & PRIO_MASK;
|
||||
|
||||
// synthesis attribute priority_extract of HIGHEST_IRQ is force;
|
||||
reg [2:0] HIGHEST_IRQ;
|
||||
|
||||
always @*
|
||||
begin
|
||||
if (MASKED_IRQS[0]) HIGHEST_IRQ <= 3'b000;
|
||||
else if (MASKED_IRQS[1]) HIGHEST_IRQ <= 3'b001;
|
||||
else if (MASKED_IRQS[2]) HIGHEST_IRQ <= 3'b010;
|
||||
else if (MASKED_IRQS[3]) HIGHEST_IRQ <= 3'b011;
|
||||
else if (MASKED_IRQS[4]) HIGHEST_IRQ <= 3'b100;
|
||||
else if (MASKED_IRQS[5]) HIGHEST_IRQ <= 3'b101;
|
||||
else if (MASKED_IRQS[6]) HIGHEST_IRQ <= 3'b110;
|
||||
else if (MASKED_IRQS[7]) HIGHEST_IRQ <= 3'b111;
|
||||
else HIGHEST_IRQ <= 3'bXXX;
|
||||
end
|
||||
|
||||
// synthesis attribute decoder_extract of HIGHEST_BIT is yes;
|
||||
reg [7:0] HIGHEST_BIT;
|
||||
|
||||
always @*
|
||||
begin
|
||||
case (HIGHEST_IRQ)
|
||||
3'b000: HIGHEST_BIT <= 8'b00000001;
|
||||
3'b001: HIGHEST_BIT <= 8'b00000010;
|
||||
3'b010: HIGHEST_BIT <= 8'b00000100;
|
||||
3'b011: HIGHEST_BIT <= 8'b00001000;
|
||||
3'b100: HIGHEST_BIT <= 8'b00010000;
|
||||
3'b101: HIGHEST_BIT <= 8'b00100000;
|
||||
3'b110: HIGHEST_BIT <= 8'b01000000;
|
||||
default: HIGHEST_BIT <= 8'b10000000;
|
||||
endcase
|
||||
end
|
||||
|
||||
wire [7:0] CLEAR_IRQS =
|
||||
(STB_I & WE_I & (ADR_I == 4'b1000) & SEL_I[0]) ? DAT_I[7:0] : 8'h00;
|
||||
|
||||
// T[x] P[x] PIRQ[x] IRQ[x] | triggered
|
||||
// 0 0 0 0 | 1
|
||||
// 0 0 0 1 | 0
|
||||
// 0 0 1 0 | 1
|
||||
// 0 0 1 1 | 0
|
||||
//
|
||||
// 0 1 0 0 | 0
|
||||
// 0 1 0 1 | 1
|
||||
// 0 1 1 0 | 0
|
||||
// 0 1 1 1 | 1
|
||||
//
|
||||
// 1 0 0 0 | 0
|
||||
// 1 0 0 1 | 0
|
||||
// 1 0 1 0 | 1
|
||||
// 1 0 1 1 | 0
|
||||
//
|
||||
// 1 1 0 0 | 0
|
||||
// 1 1 0 1 | 1
|
||||
// 1 1 1 0 | 0
|
||||
// 1 1 1 1 | 0
|
||||
|
||||
wire [7:0] TRIGGERED_IRQS;
|
||||
|
||||
generate
|
||||
genvar i;
|
||||
for (i=0; i<=7; i=i+1)
|
||||
begin : trigger_luts
|
||||
LUT4 #(
|
||||
.INIT(16'b0010_0100_1010_0101)
|
||||
) TriggerLUT (
|
||||
.I3(TRIGGER[i]),
|
||||
.I2(POLARITY[i]),
|
||||
.I1(PREV_IRQS[i]),
|
||||
.I0(IRQS[i]),
|
||||
.O(TRIGGERED_IRQS[i])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (RST_I)
|
||||
begin
|
||||
TRIGGER <= 8'h00;
|
||||
POLARITY <= 8'hFF;
|
||||
MASK <= 8'h00;
|
||||
STATUS <= 8'h00;
|
||||
PREV_IRQS <= 8'h00;
|
||||
DELIVERED <= 8'h00;
|
||||
end
|
||||
else
|
||||
begin
|
||||
STATUS <= (STATUS & ~CLEAR_IRQS) | TRIGGERED_IRQS;
|
||||
PREV_IRQS <= IRQS;
|
||||
|
||||
if (IACK_I)
|
||||
DELIVERED <= (DELIVERED & ~CLEAR_IRQS) | HIGHEST_BIT;
|
||||
else
|
||||
DELIVERED <= (DELIVERED & ~CLEAR_IRQS);
|
||||
|
||||
if (STB_I & WE_I & ~ADR_I[3])
|
||||
IADR[ADR_I[2:0]] <= DAT_I;
|
||||
|
||||
if (STB_I & WE_I & (ADR_I == 4'b1000))
|
||||
begin
|
||||
if (SEL_I[3]) TRIGGER <= DAT_I[31:24];
|
||||
if (SEL_I[2]) POLARITY <= DAT_I[23:16];
|
||||
if (SEL_I[1]) MASK <= DAT_I[15: 8];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
wire [31:0] IADR_DATA, TPMS_DATA;
|
||||
|
||||
assign IADR_O = IADR[HIGHEST_IRQ];
|
||||
assign IADR_DATA = IADR[ADR_I[2:0]];
|
||||
assign IRQ_O = |MASKED_IRQS;
|
||||
assign ACK_O = STB_I;
|
||||
assign TPMS_DATA = { TRIGGER, POLARITY, MASK, STATUS };
|
||||
assign DAT_O = ~ADR_I[3] ? IADR_DATA : TPMS_DATA;
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
// Computes the number of leading zeros in the input. Result is 0...32.
|
||||
module NLZ (IN, OUT);
|
||||
|
||||
input [31:0] IN;
|
||||
output [5:0] OUT;
|
||||
|
||||
wire [7:0] PARTS = {
|
||||
|IN[31:28], |IN[27:24], |IN[23:20], |IN[19:16],
|
||||
|IN[15:12], |IN[11: 8], |IN[ 7: 4], |IN[ 3: 0]
|
||||
};
|
||||
|
||||
// synthesis attribute priority_extract of LEADING_PARTS is force;
|
||||
reg [2:0] LEADING_PARTS;
|
||||
reg [1:0] LEADING_BITS;
|
||||
reg [3:0] PART;
|
||||
|
||||
always @*
|
||||
begin
|
||||
if (PARTS[7]) LEADING_PARTS <= 3'b000;
|
||||
else if (PARTS[6]) LEADING_PARTS <= 3'b001;
|
||||
else if (PARTS[5]) LEADING_PARTS <= 3'b010;
|
||||
else if (PARTS[4]) LEADING_PARTS <= 3'b011;
|
||||
else if (PARTS[3]) LEADING_PARTS <= 3'b100;
|
||||
else if (PARTS[2]) LEADING_PARTS <= 3'b101;
|
||||
else if (PARTS[1]) LEADING_PARTS <= 3'b110;
|
||||
else if (PARTS[0]) LEADING_PARTS <= 3'b111;
|
||||
else LEADING_PARTS <= 3'bXXX;
|
||||
|
||||
case (LEADING_PARTS)
|
||||
3'b000: PART <= IN[31:28];
|
||||
3'b001: PART <= IN[27:24];
|
||||
3'b010: PART <= IN[23:20];
|
||||
3'b011: PART <= IN[19:16];
|
||||
3'b100: PART <= IN[15:12];
|
||||
3'b101: PART <= IN[11: 8];
|
||||
3'b110: PART <= IN[ 7: 4];
|
||||
3'b111: PART <= IN[ 3: 0];
|
||||
endcase
|
||||
|
||||
casex (PART)
|
||||
4'b1XXX: LEADING_BITS <= 2'b00;
|
||||
4'b01XX: LEADING_BITS <= 2'b01;
|
||||
4'b001X: LEADING_BITS <= 2'b10;
|
||||
4'b000X: LEADING_BITS <= 2'b11;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign OUT = (~|PARTS) ? 6'd32 : { LEADING_PARTS, LEADING_BITS };
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
module ProgramRAM (CLK_I,RST_I,INST_ADR_I,INST_DAT_O,INST_STB_I,INST_ACK_O,
|
||||
DATA_ADR_I,DATA_DAT_I,DATA_DAT_O,DATA_STB_I,DATA_WE_I,DATA_SEL_I,DATA_ACK_O);
|
||||
|
||||
input CLK_I;
|
||||
input RST_I;
|
||||
|
||||
input [12:0] INST_ADR_I;
|
||||
output [7:0] INST_DAT_O;
|
||||
input INST_STB_I;
|
||||
output INST_ACK_O;
|
||||
|
||||
input [12:2] DATA_ADR_I;
|
||||
input [31:0] DATA_DAT_I;
|
||||
output [31:0] DATA_DAT_O;
|
||||
input DATA_STB_I;
|
||||
input DATA_WE_I;
|
||||
input [3:0] DATA_SEL_I;
|
||||
output DATA_ACK_O;
|
||||
|
||||
// synthesis attribute ram_style of RAM is block;
|
||||
reg [31:0] RAM[0:2047];
|
||||
reg [12:2] READ_INST;
|
||||
reg [12:2] READ_DATA;
|
||||
|
||||
reg [7:0] INST_DAT_O;
|
||||
reg INST_ACK_O;
|
||||
|
||||
wire [31:0] DATA_DAT_O;
|
||||
reg DATA_ACK_O;
|
||||
|
||||
initial
|
||||
begin
|
||||
$readmemh("program.data", RAM, 0, 2047);
|
||||
end
|
||||
|
||||
reg [12:2] INST_PRED_ADR;
|
||||
|
||||
wire WORD_ACCESS = &DATA_SEL_I;
|
||||
reg DATA_READ = 1'b0;
|
||||
reg [31:0] RMW_DATA;
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (DATA_STB_I & DATA_WE_I & (WORD_ACCESS | DATA_READ))
|
||||
RAM[DATA_ADR_I] <= WORD_ACCESS ? DATA_DAT_I : RMW_DATA;
|
||||
|
||||
READ_DATA <= DATA_ADR_I[12:2];
|
||||
READ_INST <= INST_PRED_ADR[12:2];
|
||||
|
||||
DATA_READ <= DATA_STB_I & ~DATA_ACK_O;
|
||||
end
|
||||
|
||||
wire [31:0] INST_DAT32_O;
|
||||
|
||||
assign INST_DAT32_O = RAM[READ_INST];
|
||||
assign DATA_DAT_O = RAM[READ_DATA];
|
||||
|
||||
wire [12:0] NEXT_INST_ADR = INST_ADR_I + 13'd1;
|
||||
wire PRED_CORRECT = (READ_INST == INST_ADR_I[12:2]);
|
||||
|
||||
wire READ_DONE = DATA_READ;
|
||||
wire WRITE_DONE = WORD_ACCESS | DATA_READ;
|
||||
|
||||
always @*
|
||||
begin
|
||||
case (INST_ADR_I[1:0])
|
||||
2'b00: INST_DAT_O <= INST_DAT32_O[31:24];
|
||||
2'b01: INST_DAT_O <= INST_DAT32_O[23:16];
|
||||
2'b10: INST_DAT_O <= INST_DAT32_O[15:8];
|
||||
2'b11: INST_DAT_O <= INST_DAT32_O[7:0];
|
||||
endcase
|
||||
|
||||
if (~INST_STB_I | PRED_CORRECT)
|
||||
INST_PRED_ADR <= NEXT_INST_ADR[12:2];
|
||||
else // incorrectly predicted, forces wait state
|
||||
INST_PRED_ADR <= INST_ADR_I[12:2];
|
||||
|
||||
INST_ACK_O <= INST_STB_I & PRED_CORRECT;
|
||||
DATA_ACK_O <= DATA_STB_I & (DATA_WE_I ? WRITE_DONE : READ_DONE);
|
||||
|
||||
RMW_DATA[31:24] <= DATA_SEL_I[3] ? DATA_DAT_I[31:24] : DATA_DAT_O[31:24];
|
||||
RMW_DATA[23:16] <= DATA_SEL_I[2] ? DATA_DAT_I[23:16] : DATA_DAT_O[23:16];
|
||||
RMW_DATA[15: 8] <= DATA_SEL_I[1] ? DATA_DAT_I[15: 8] : DATA_DAT_O[15: 8];
|
||||
RMW_DATA[ 7: 0] <= DATA_SEL_I[0] ? DATA_DAT_I[ 7: 0] : DATA_DAT_O[ 7: 0];
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
// synthesis attribute slice_utilization_ratio of RS232 is 7;
|
||||
module RS232 (CLK_I, RST_I, DAT_I, DAT_O, STB_I, WE_I, SEL_I, ACK_O,
|
||||
TX_EMPTY, TX_FULL, RX_EMPTY, RX_FULL, RX, TX);
|
||||
|
||||
//parameter CLOCK_DIV = 5207; // 9600 bps @ 50 MHz CLK_I
|
||||
parameter CLOCK_DIV = 434; // 115200 bps @ 50 MHz CLK_I
|
||||
|
||||
input CLK_I;
|
||||
input RST_I;
|
||||
input [31:0] DAT_I;
|
||||
output [31:0] DAT_O;
|
||||
input STB_I;
|
||||
input WE_I;
|
||||
input [3:0] SEL_I;
|
||||
output ACK_O;
|
||||
output TX_EMPTY, TX_FULL;
|
||||
output RX_EMPTY, RX_FULL;
|
||||
input RX;
|
||||
output TX;
|
||||
|
||||
reg TX = 1'b1;
|
||||
|
||||
`define IDLE 4'd0
|
||||
`define START 4'd1
|
||||
`define BIT0 4'd2
|
||||
`define BIT1 4'd3
|
||||
`define BIT2 4'd4
|
||||
`define BIT3 4'd5
|
||||
`define BIT4 4'd6
|
||||
`define BIT5 4'd7
|
||||
`define BIT6 4'd8
|
||||
`define BIT7 4'd9
|
||||
`define STOP 4'd10
|
||||
|
||||
reg [17:0] TX_COUNTER;
|
||||
reg [9:0] TX_BUFFER;
|
||||
reg [3:0] TX_STATE = `IDLE;
|
||||
|
||||
reg [18:0] RX_COUNTER;
|
||||
reg [6:0] RX_BUFFER;
|
||||
reg [3:0] RX_STATE = `IDLE;
|
||||
|
||||
wire [7:0] TX_DATA;
|
||||
wire [7:0] RX_DATA;
|
||||
|
||||
FIFO #(
|
||||
.QUEUE_SIZE(4), // 16 characters
|
||||
.DATA_WIDTH(8)
|
||||
) TransmitFIFO (
|
||||
.CLK_I(CLK_I),
|
||||
.RST_I(RST_I),
|
||||
.DAT_I(DAT_I[7:0]),
|
||||
.DAT_O(TX_DATA),
|
||||
.QUEUE_I(ACK_O & WE_I & SEL_I[0]),
|
||||
.DEQUEUE_I(TX_STATE == `IDLE),
|
||||
.FULL_O(TX_FULL),
|
||||
.EMPTY_O(TX_EMPTY)
|
||||
);
|
||||
|
||||
FIFO #(
|
||||
.QUEUE_SIZE(4), // 16 characters
|
||||
.DATA_WIDTH(8)
|
||||
) ReceiveFIFO (
|
||||
.CLK_I(CLK_I),
|
||||
.RST_I(RST_I),
|
||||
.DAT_I({ RX, RX_BUFFER }),
|
||||
.DAT_O(RX_DATA),
|
||||
.QUEUE_I((RX_STATE == `BIT7) & (RX_COUNTER == 0)),
|
||||
.DEQUEUE_I(ACK_O & ~WE_I & SEL_I[0]),
|
||||
.FULL_O(RX_FULL),
|
||||
.EMPTY_O(RX_EMPTY)
|
||||
);
|
||||
|
||||
assign DAT_O = { 22'h000000, TX_FULL, ~RX_EMPTY, RX_DATA };
|
||||
assign ACK_O = STB_I;
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (TX_STATE == `IDLE)
|
||||
begin
|
||||
TX <= 1'b1;
|
||||
TX_COUNTER <= (CLOCK_DIV - 1);
|
||||
|
||||
if (~TX_EMPTY)
|
||||
begin
|
||||
TX_BUFFER <= { 1'b1, 1'b1, TX_DATA, 1'b0 };
|
||||
TX_STATE <= `START;
|
||||
end
|
||||
end
|
||||
else if (~|TX_COUNTER)
|
||||
begin
|
||||
TX <= TX_BUFFER[0];
|
||||
TX_BUFFER <= TX_BUFFER >> 1;
|
||||
TX_COUNTER <= (CLOCK_DIV - 1);
|
||||
|
||||
if (TX_STATE == `STOP)
|
||||
TX_STATE <= `IDLE;
|
||||
else
|
||||
TX_STATE <= TX_STATE + 1;
|
||||
end
|
||||
else
|
||||
TX_COUNTER <= TX_COUNTER - 1;
|
||||
end
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if ((RX_STATE == `IDLE) | RST_I)
|
||||
begin
|
||||
RX_COUNTER <= (CLOCK_DIV / 2);
|
||||
|
||||
if (RX == 1'b0)
|
||||
RX_STATE <= `START;
|
||||
else
|
||||
RX_STATE <= `IDLE;
|
||||
end
|
||||
else if (RX_COUNTER == 0)
|
||||
begin
|
||||
RX_BUFFER <= { RX, RX_BUFFER[6:1] };
|
||||
RX_COUNTER <= (CLOCK_DIV - 1);
|
||||
|
||||
if (RX_STATE == `STOP)
|
||||
RX_STATE <= `IDLE;
|
||||
else
|
||||
RX_STATE <= RX_STATE + 1;
|
||||
end
|
||||
else
|
||||
RX_COUNTER <= RX_COUNTER - 1;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
module SevenSeg (CLKIN, INPUT, DP, SEG, ANODE);
|
||||
|
||||
input CLKIN;
|
||||
input [15:0] INPUT;
|
||||
input [3:0] DP;
|
||||
output [7:0] SEG;
|
||||
output [3:0] ANODE;
|
||||
|
||||
reg [7:0] SEG = 1'b1;
|
||||
reg [3:0] ANODE = 4'b1111;
|
||||
|
||||
reg [18:0] CNT;
|
||||
wire [1:0] SEG_SEL = CNT[18:17];
|
||||
reg [3:0] SEG_BIN;
|
||||
|
||||
always @*
|
||||
begin
|
||||
case (SEG_SEL)
|
||||
2'b00: SEG_BIN <= INPUT[15:12];
|
||||
2'b01: SEG_BIN <= INPUT[11:8];
|
||||
2'b10: SEG_BIN <= INPUT[7:4];
|
||||
2'b11: SEG_BIN <= INPUT[3:0];
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge CLKIN)
|
||||
begin
|
||||
CNT <= CNT + 1;
|
||||
|
||||
casex (SEG_SEL)
|
||||
2'b00: ANODE <= 4'b0111;
|
||||
2'b01: ANODE <= 4'b1011;
|
||||
2'b10: ANODE <= 4'b1101;
|
||||
2'b11: ANODE <= 4'b1110;
|
||||
endcase
|
||||
|
||||
case (SEG_BIN)
|
||||
4'h0: SEG[7:1] <= 8'b0000001;
|
||||
4'h1: SEG[7:1] <= 8'b1001111;
|
||||
4'h2: SEG[7:1] <= 8'b0010010;
|
||||
4'h3: SEG[7:1] <= 8'b0000110;
|
||||
4'h4: SEG[7:1] <= 8'b1001100;
|
||||
4'h5: SEG[7:1] <= 8'b0100100;
|
||||
4'h6: SEG[7:1] <= 8'b0100000;
|
||||
4'h7: SEG[7:1] <= 8'b0001111;
|
||||
4'h8: SEG[7:1] <= 8'b0000000;
|
||||
4'h9: SEG[7:1] <= 8'b0000100;
|
||||
4'hA: SEG[7:1] <= 8'b0001000;
|
||||
4'hB: SEG[7:1] <= 8'b1100000;
|
||||
4'hC: SEG[7:1] <= 8'b0110001;
|
||||
4'hD: SEG[7:1] <= 8'b1000010;
|
||||
4'hE: SEG[7:1] <= 8'b0110000;
|
||||
4'hF: SEG[7:1] <= 8'b0111000;
|
||||
endcase
|
||||
|
||||
case (SEG_SEL)
|
||||
2'b00: SEG[0] <= ~DP[3];
|
||||
2'b01: SEG[0] <= ~DP[2];
|
||||
2'b10: SEG[0] <= ~DP[1];
|
||||
2'b11: SEG[0] <= ~DP[0];
|
||||
endcase
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
module WB_SRAM (CLK_I, RST_I, ADR_I, DAT_I, DAT_O, STB_I, WE_I, SEL_I, ACK_O,
|
||||
SRAM_IO1, SRAM_CE1, SRAM_UB1, SRAM_LB1, SRAM_ADR, SRAM_WE, SRAM_OE,
|
||||
SRAM_IO2, SRAM_CE2, SRAM_UB2, SRAM_LB2);
|
||||
|
||||
// Wishbone signals
|
||||
input CLK_I, RST_I, STB_I, WE_I;
|
||||
input [17:0] ADR_I;
|
||||
input [31:0] DAT_I;
|
||||
output [31:0] DAT_O;
|
||||
input [3:0] SEL_I;
|
||||
output ACK_O;
|
||||
|
||||
// SRAM signals
|
||||
output [17:0] SRAM_ADR;
|
||||
output SRAM_WE, SRAM_OE;
|
||||
inout [15:0] SRAM_IO1, SRAM_IO2;
|
||||
output SRAM_CE1, SRAM_CE2;
|
||||
output SRAM_UB1, SRAM_UB2;
|
||||
output SRAM_LB1, SRAM_LB2;
|
||||
|
||||
assign SRAM_CE1 = 1'b0;
|
||||
assign SRAM_CE2 = 1'b0;
|
||||
|
||||
// synthesis attribute iob of SRAM_ADR_O is true;
|
||||
// synthesis attribute iob of SRAM_DAT_O is true;
|
||||
// synthesis attribute iob of SRAM_SEL_O is true;
|
||||
// synthesis attribute iob of SRAM_OE_O is true;
|
||||
// synthesis attribute iob of SRAM_WE_O is true;
|
||||
// synthesis attribute iob of HIGH_Z is true;
|
||||
|
||||
reg [17:0] SRAM_ADR_O;
|
||||
reg [31:0] SRAM_DAT_O;
|
||||
wire [31:0] SRAM_DAT_I;
|
||||
reg [3:0] SRAM_SEL_O;
|
||||
reg HIGH_Z = 1'b1;
|
||||
|
||||
assign SRAM_UB1 = SRAM_SEL_O[3];
|
||||
assign SRAM_LB1 = SRAM_SEL_O[2];
|
||||
assign SRAM_UB2 = SRAM_SEL_O[1];
|
||||
assign SRAM_LB2 = SRAM_SEL_O[0];
|
||||
|
||||
assign SRAM_ADR = SRAM_ADR_O;
|
||||
|
||||
assign SRAM_IO1 = HIGH_Z ? 16'dZ : SRAM_DAT_O[31:16];
|
||||
assign SRAM_IO2 = HIGH_Z ? 16'dZ : SRAM_DAT_O[15: 0];
|
||||
assign SRAM_DAT_I = { SRAM_IO1, SRAM_IO2 };
|
||||
|
||||
`define SRS_IDLE 2'd0
|
||||
`define SRS_READ 2'd1
|
||||
`define SRS_WRITE 2'd2
|
||||
reg [1:0] STATE = `SRS_IDLE;
|
||||
|
||||
reg SRAM_WE = 1'b1;
|
||||
reg SRAM_OE = 1'b1;
|
||||
reg ACK_O = 1'b0;
|
||||
|
||||
reg [31:0] DAT_O;
|
||||
|
||||
always @(negedge CLK_I)
|
||||
SRAM_WE <= ~(STATE == `SRS_WRITE);
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
DAT_O <= SRAM_DAT_I;
|
||||
|
||||
if (RST_I)
|
||||
begin
|
||||
SRAM_OE <= 1'b1;
|
||||
HIGH_Z <= 1'b1;
|
||||
ACK_O <= 1'b0;
|
||||
STATE <= `SRS_IDLE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
case (STATE)
|
||||
`SRS_IDLE:
|
||||
begin
|
||||
SRAM_ADR_O <= ADR_I;
|
||||
SRAM_DAT_O <= DAT_I;
|
||||
SRAM_SEL_O <= ~SEL_I;
|
||||
ACK_O <= 1'b0;
|
||||
|
||||
if (STB_I)
|
||||
begin
|
||||
if (WE_I)
|
||||
begin
|
||||
SRAM_OE <= 1'b1;
|
||||
HIGH_Z <= 1'b0;
|
||||
STATE <= `SRS_WRITE;
|
||||
end
|
||||
else
|
||||
begin
|
||||
SRAM_OE <= 1'b0;
|
||||
HIGH_Z <= 1'b1;
|
||||
STATE <= `SRS_READ;
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
SRAM_OE <= 1'b1;
|
||||
HIGH_Z <= 1'b1;
|
||||
STATE <= `SRS_IDLE;
|
||||
end
|
||||
end
|
||||
`SRS_READ:
|
||||
begin
|
||||
SRAM_OE <= 1'b1;
|
||||
HIGH_Z <= 1'b1;
|
||||
ACK_O <= 1'b1;
|
||||
STATE <= `SRS_IDLE;
|
||||
end
|
||||
`SRS_WRITE:
|
||||
begin
|
||||
SRAM_OE <= 1'b1;
|
||||
HIGH_Z <= 1'b1;
|
||||
ACK_O <= 1'b1;
|
||||
STATE <= `SRS_IDLE;
|
||||
end
|
||||
default:
|
||||
STATE <= `SRS_IDLE;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
module StackRAM (CLKIN, ADDR_A, WE_A, IN_A, OUT_A, ADDR_B, OUT_B);
|
||||
|
||||
parameter ADDR_WIDTH = 9;
|
||||
parameter DATA_WIDTH = 32;
|
||||
|
||||
input CLKIN;
|
||||
input [ADDR_WIDTH-1:0] ADDR_A;
|
||||
input WE_A;
|
||||
input [DATA_WIDTH-1:0] IN_A;
|
||||
output [DATA_WIDTH-1:0] OUT_A;
|
||||
input [ADDR_WIDTH-1:0] ADDR_B;
|
||||
output [DATA_WIDTH-1:0] OUT_B;
|
||||
|
||||
reg [DATA_WIDTH-1:0] RAM[0:(1<<ADDR_WIDTH)-1];
|
||||
reg [ADDR_WIDTH-1:0] READ_A;
|
||||
reg [ADDR_WIDTH-1:0] READ_B;
|
||||
|
||||
assign OUT_A = RAM[READ_A];
|
||||
assign OUT_B = RAM[READ_B];
|
||||
|
||||
always @(posedge CLKIN)
|
||||
begin
|
||||
if (WE_A)
|
||||
RAM[ADDR_A] <= IN_A;
|
||||
|
||||
READ_A <= ADDR_A;
|
||||
end
|
||||
|
||||
always @(negedge CLKIN)
|
||||
begin
|
||||
READ_B <= ADDR_B;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
module TIMER (CLK_I,RST_I,ADR_I,DAT_I,DAT_O,STB_I,WE_I,ACK_O,IRQ_O);
|
||||
|
||||
parameter INIT_RELOAD = 0;
|
||||
|
||||
input CLK_I, RST_I, STB_I, WE_I;
|
||||
input [1:0] ADR_I;
|
||||
input [31:0] DAT_I;
|
||||
output [31:0] DAT_O;
|
||||
output ACK_O, IRQ_O;
|
||||
|
||||
reg [31:0] RELOAD = INIT_RELOAD;
|
||||
reg [31:0] COUNTER = INIT_RELOAD;
|
||||
reg [63:0] TIMEBASE = 64'd0;
|
||||
|
||||
wire ZERO = ~|COUNTER;
|
||||
|
||||
assign ACK_O = STB_I;
|
||||
assign IRQ_O = ZERO & ~RST_I;
|
||||
|
||||
reg [31:0] DAT_O;
|
||||
|
||||
always @*
|
||||
begin
|
||||
case (ADR_I)
|
||||
2'd0: DAT_O <= COUNTER;
|
||||
2'd1: DAT_O <= RELOAD;
|
||||
2'd2: DAT_O <= TIMEBASE[63:32];
|
||||
2'd3: DAT_O <= TIMEBASE[31:0];
|
||||
endcase
|
||||
end
|
||||
|
||||
always @(posedge CLK_I)
|
||||
begin
|
||||
if (RST_I)
|
||||
begin
|
||||
RELOAD <= INIT_RELOAD;
|
||||
COUNTER <= INIT_RELOAD;
|
||||
TIMEBASE <= 64'd0;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (STB_I & WE_I & ~ADR_I[1] & ~ADR_I[0])
|
||||
COUNTER <= DAT_I;
|
||||
else if (ZERO | RST_I)
|
||||
COUNTER <= RELOAD;
|
||||
else
|
||||
COUNTER <= COUNTER - 1;
|
||||
|
||||
if (STB_I & WE_I & ~ADR_I[1] & ADR_I[0])
|
||||
RELOAD <= DAT_I;
|
||||
|
||||
if (STB_I & WE_I & ADR_I[1] & ~ADR_I[0])
|
||||
TIMEBASE <= { DAT_I, 32'd0 };
|
||||
else if (STB_I & WE_I & ADR_I[1] & ADR_I[0])
|
||||
TIMEBASE <= { TIMEBASE[63:32], DAT_I };
|
||||
else
|
||||
TIMEBASE <= TIMEBASE + 1;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
verilog work cpu.v
|
||||
verilog work stack.v
|
||||
verilog work nlz.v
|
||||
verilog work program.v
|
||||
verilog work toplevel.v
|
||||
verilog work seven-seg.v
|
||||
verilog work rs232.v
|
||||
verilog work fifo.v
|
||||
verilog work sram.v
|
||||
verilog work irq_ctl.v
|
||||
verilog work arbiter.v
|
||||
verilog work dma.v
|
||||
verilog work timer.v
|
||||
|
|
@ -0,0 +1,209 @@
|
|||
#######################################################################
|
||||
# #
|
||||
# Pin Description for the Spartan-3 Starter Kit Board #
|
||||
# #
|
||||
#######################################################################
|
||||
|
||||
#
|
||||
# 50 MHz on-board clock source
|
||||
#
|
||||
NET "CLKIN" LOC = T9;
|
||||
NET "CLKIN" TNM_NET = "CLKIN";
|
||||
TIMESPEC "TS_CLKIN" = PERIOD "CLKIN" 20 ns HIGH 50%;
|
||||
|
||||
OFFSET = OUT 20 ns AFTER "CLKIN";
|
||||
|
||||
#
|
||||
# On-board Static RAM
|
||||
#
|
||||
TIMEGRP "SRAM_ADR" = PADS("SRAM_ADR<*>");
|
||||
TIMEGRP "SRAM_IO" = PADS("SRAM_IO?<*>");
|
||||
TIMEGRP "SRAM_CE" = PADS("SRAM_CE?");
|
||||
TIMEGRP "SRAM_BE" = PADS("SRAM_UB?") PADS("SRAM_LB?");
|
||||
TIMEGRP "SRAM_WE" = PADS("SRAM_WE");
|
||||
TIMEGRP "SRAM_OE" = PADS("SRAM_OE");
|
||||
|
||||
TIMEGRP "SRAM_ADR" OFFSET = OUT 6.0 ns AFTER "CLKIN";
|
||||
TIMEGRP "SRAM_IO" OFFSET = IN 15.0 ns VALID 20 ns AFTER "CLKIN";
|
||||
#TIMEGRP "SRAM_CE" OFFSET = OUT 2.0 ns AFTER "CLKIN";
|
||||
TIMEGRP "SRAM_BE" OFFSET = OUT 8.0 ns AFTER "CLKIN";
|
||||
TIMEGRP "SRAM_OE" OFFSET = OUT 8.0 ns AFTER "CLKIN";
|
||||
|
||||
TIMEGRP "SRAM_IO" OFFSET = OUT 14.0 ns AFTER "CLKIN";
|
||||
TIMEGRP "SRAM_WE" OFFSET = OUT 18.0 ns AFTER "CLKIN";
|
||||
|
||||
NET "SRAM_ADR<*>" DRIVE = 4;
|
||||
NET "SRAM_IO1<*>" DRIVE = 4;
|
||||
NET "SRAM_IO2<*>" DRIVE = 4;
|
||||
NET "SRAM_CE?" DRIVE = 4;
|
||||
NET "SRAM_UB?" DRIVE = 4;
|
||||
NET "SRAM_LB?" DRIVE = 4;
|
||||
NET "SRAM_WE" DRIVE = 4;
|
||||
NET "SRAM_OE" DRIVE = 4;
|
||||
|
||||
NET "SRAM_ADR<*>" FAST;
|
||||
NET "SRAM_IO1<*>" FAST;
|
||||
NET "SRAM_IO2<*>" FAST;
|
||||
NET "SRAM_CE?" FAST;
|
||||
NET "SRAM_UB?" FAST;
|
||||
NET "SRAM_LB?" FAST;
|
||||
NET "SRAM_WE" FAST;
|
||||
NET "SRAM_OE" FAST;
|
||||
|
||||
NET "SRAM_ADR<17>" LOC = L3; # Address to SRAM bus
|
||||
NET "SRAM_ADR<16>" LOC = K5;
|
||||
NET "SRAM_ADR<15>" LOC = K3;
|
||||
NET "SRAM_ADR<14>" LOC = J3;
|
||||
NET "SRAM_ADR<13>" LOC = J4;
|
||||
NET "SRAM_ADR<12>" LOC = H4;
|
||||
NET "SRAM_ADR<11>" LOC = H3;
|
||||
NET "SRAM_ADR<10>" LOC = G5;
|
||||
NET "SRAM_ADR<9>" LOC = E4;
|
||||
NET "SRAM_ADR<8>" LOC = E3;
|
||||
NET "SRAM_ADR<7>" LOC = F4;
|
||||
NET "SRAM_ADR<6>" LOC = F3;
|
||||
NET "SRAM_ADR<5>" LOC = G4;
|
||||
NET "SRAM_ADR<4>" LOC = L4;
|
||||
NET "SRAM_ADR<3>" LOC = M3;
|
||||
NET "SRAM_ADR<2>" LOC = M4;
|
||||
NET "SRAM_ADR<1>" LOC = N3;
|
||||
NET "SRAM_ADR<0>" LOC = L5;
|
||||
|
||||
NET "SRAM_IO1<15>" LOC = R1; # Data to and/or from SRAM #1
|
||||
NET "SRAM_IO1<14>" LOC = P1;
|
||||
NET "SRAM_IO1<13>" LOC = L2;
|
||||
NET "SRAM_IO1<12>" LOC = J2;
|
||||
NET "SRAM_IO1<11>" LOC = H1;
|
||||
NET "SRAM_IO1<10>" LOC = F2;
|
||||
NET "SRAM_IO1<9>" LOC = P8;
|
||||
NET "SRAM_IO1<8>" LOC = D3;
|
||||
NET "SRAM_IO1<7>" LOC = B1;
|
||||
NET "SRAM_IO1<6>" LOC = C1;
|
||||
NET "SRAM_IO1<5>" LOC = C2;
|
||||
NET "SRAM_IO1<4>" LOC = R5;
|
||||
NET "SRAM_IO1<3>" LOC = T5;
|
||||
NET "SRAM_IO1<2>" LOC = R6;
|
||||
NET "SRAM_IO1<1>" LOC = T8;
|
||||
NET "SRAM_IO1<0>" LOC = N7;
|
||||
|
||||
NET "SRAM_CE1" LOC = P7; # Control signals to SRAM #1
|
||||
NET "SRAM_UB1" LOC = T4;
|
||||
NET "SRAM_LB1" LOC = P6;
|
||||
|
||||
NET "SRAM_IO2<15>" LOC = N1; # Data to/from SRAM #2
|
||||
NET "SRAM_IO2<14>" LOC = M1;
|
||||
NET "SRAM_IO2<13>" LOC = K2;
|
||||
NET "SRAM_IO2<12>" LOC = C3;
|
||||
NET "SRAM_IO2<11>" LOC = F5;
|
||||
NET "SRAM_IO2<10>" LOC = G1;
|
||||
NET "SRAM_IO2<9>" LOC = E2;
|
||||
NET "SRAM_IO2<8>" LOC = D2;
|
||||
NET "SRAM_IO2<7>" LOC = D1;
|
||||
NET "SRAM_IO2<6>" LOC = E1;
|
||||
NET "SRAM_IO2<5>" LOC = G2;
|
||||
NET "SRAM_IO2<4>" LOC = J1;
|
||||
NET "SRAM_IO2<3>" LOC = K1;
|
||||
NET "SRAM_IO2<2>" LOC = M2;
|
||||
NET "SRAM_IO2<1>" LOC = N2;
|
||||
NET "SRAM_IO2<0>" LOC = P2;
|
||||
|
||||
NET "SRAM_CE2" LOC = N5; # Control signals to SRAM #2
|
||||
NET "SRAM_UB2" LOC = R4;
|
||||
NET "SRAM_LB2" LOC = P5;
|
||||
|
||||
NET "SRAM_WE" LOC = G3; # Control signals to SRAMs #1 and #2
|
||||
NET "SRAM_OE" LOC = K4;
|
||||
|
||||
#
|
||||
# RS-232 Serial Port (w/ DB-9)
|
||||
#
|
||||
TIMEGRP "RS232" = PADS("RX_A") PADS("TX_A");
|
||||
NET "TX_A" DRIVE = 4;
|
||||
|
||||
NET "RX_A" LOC = T13; # serial input from V.24 driver
|
||||
NET "TX_A" LOC = R13; # serial output to V.24 driver
|
||||
|
||||
#
|
||||
# On-board LEDs
|
||||
#
|
||||
TIMEGRP "LEDS" = PADS("LED<*>");
|
||||
NET "LED<*>" DRIVE = 4;
|
||||
|
||||
NET "LED<7>" LOC = P11; # signal to 8 LEDs (7 is leftmost)
|
||||
NET "LED<6>" LOC = P12;
|
||||
NET "LED<5>" LOC = N12;
|
||||
NET "LED<4>" LOC = P13;
|
||||
NET "LED<3>" LOC = N14;
|
||||
NET "LED<2>" LOC = L12;
|
||||
NET "LED<1>" LOC = P14;
|
||||
NET "LED<0>" LOC = K12;
|
||||
|
||||
#
|
||||
# On-board 7-segment LED displays
|
||||
#
|
||||
TIMEGRP "DISPLAY" = PADS("SEG<*>") PADS("ANODE<*>");
|
||||
NET "SEG<*>" DRIVE = 4;
|
||||
NET "ANODE<*>" DRIVE = 4;
|
||||
|
||||
NET "SEG<7>" LOC = E14; # (a) signal to 7-segment displays
|
||||
NET "SEG<6>" LOC = G13; # (b)
|
||||
NET "SEG<5>" LOC = N15; # (c) Note: active-low outputs
|
||||
NET "SEG<4>" LOC = P15; # (d)
|
||||
NET "SEG<3>" LOC = R16; # (e)
|
||||
NET "SEG<2>" LOC = F13; # (f)
|
||||
NET "SEG<1>" LOC = N16; # (g)
|
||||
NET "SEG<0>" LOC = P16; # (dp)
|
||||
|
||||
NET "ANODE<3>" LOC = E13; # selector for SEG<> (3 is leftmost)
|
||||
NET "ANODE<2>" LOC = F14;
|
||||
NET "ANODE<1>" LOC = G14; # Note: active-low outputs
|
||||
NET "ANODE<0>" LOC = D14;
|
||||
|
||||
#
|
||||
# On-board slide switches
|
||||
#
|
||||
TIMEGRP "SWITCHES" = PADS("SWITCH<*>");
|
||||
|
||||
NET "SWITCH<7>" LOC = K13; # signal from slide switches (7 is leftmost)
|
||||
NET "SWITCH<6>" LOC = K14;
|
||||
NET "SWITCH<5>" LOC = J13;
|
||||
NET "SWITCH<4>" LOC = J14;
|
||||
NET "SWITCH<3>" LOC = H13;
|
||||
NET "SWITCH<2>" LOC = H14;
|
||||
NET "SWITCH<1>" LOC = G12;
|
||||
NET "SWITCH<0>" LOC = F12;
|
||||
|
||||
#
|
||||
# On-board pushbuttons
|
||||
#
|
||||
TIMEGRP "BUTTONS" = PADS("BTN<*>");
|
||||
|
||||
NET "BTN<3>" LOC = L14; # signal from push-buttons (3 is leftmost)
|
||||
NET "BTN<2>" LOC = L13;
|
||||
NET "BTN<1>" LOC = M14;
|
||||
NET "BTN<0>" LOC = M13;
|
||||
|
||||
#
|
||||
# On-board 3-bit VGA port
|
||||
#
|
||||
|
||||
#TIMEGRP "VGA" = PADS("VGA_*");
|
||||
|
||||
#NET "VGA_*" DRIVE = 4;
|
||||
|
||||
#NET "VGA_RED" LOC = R12; # Output to 3-bit VGA display interface
|
||||
#NET "VGA_GREEN" LOC = T12;
|
||||
#NET "VGA_BLUE" LOC = R11;
|
||||
#NET "VGA_H_SYNC" LOC = R9;
|
||||
#NET "VGA_V_SYNC" LOC = T10;
|
||||
|
||||
#
|
||||
# On-board PS/2 keyboard/mouse port
|
||||
#
|
||||
|
||||
#TIMEGRP "PS2" = PADS("PS2_*");
|
||||
|
||||
#NET "PS2_CLK" DRIVE = 4;
|
||||
|
||||
#NET "PS2_DATA" LOC = M15; # Input from PS/2 keyboard/mouse port
|
||||
#NET "PS2_CLK" LOC = M16;
|
||||
|
|
@ -0,0 +1,416 @@
|
|||
module TopLevel (CLKIN, BTN, SWITCH, LED, SEG, ANODE, RX_A, TX_A,
|
||||
SRAM_IO1, SRAM_CE1, SRAM_UB1, SRAM_LB1, SRAM_ADR, SRAM_WE, SRAM_OE,
|
||||
SRAM_IO2, SRAM_CE2, SRAM_UB2, SRAM_LB2);
|
||||
|
||||
input CLKIN;
|
||||
|
||||
input [3:0] BTN;
|
||||
input [7:0] SWITCH;
|
||||
output [7:0] LED;
|
||||
|
||||
output [7:0] SEG;
|
||||
output [3:0] ANODE;
|
||||
|
||||
input RX_A;
|
||||
output TX_A;
|
||||
|
||||
output [17:0] SRAM_ADR;
|
||||
output SRAM_WE;
|
||||
output SRAM_OE;
|
||||
inout [15:0] SRAM_IO1;
|
||||
output SRAM_CE1;
|
||||
output SRAM_UB1;
|
||||
output SRAM_LB1;
|
||||
inout [15:0] SRAM_IO2;
|
||||
output SRAM_CE2;
|
||||
output SRAM_UB2;
|
||||
output SRAM_LB2;
|
||||
|
||||
DCM #(
|
||||
.CLKFX_DIVIDE(2), // Can be any integer from 1 to 32
|
||||
.CLKFX_MULTIPLY(2), // Can be any integer from 2 to 32
|
||||
.CLKIN_PERIOD(20.0), // Period of input clock
|
||||
.STARTUP_WAIT("TRUE"), // Delay configuration DONE until DCM LOCK?
|
||||
.CLKDV_DIVIDE(2.0), // [1.5,7.5]/0.5 or [8.0,16.0]/1.0
|
||||
.CLKIN_DIVIDE_BY_2("FALSE"), // Enable CLKIN divide-by-two feature?
|
||||
.CLKOUT_PHASE_SHIFT("NONE"), // NONE, FIXED or VARIABLE
|
||||
.CLK_FEEDBACK("1X"), // Specify clock feedback of NONE, 1X or 2X
|
||||
.PHASE_SHIFT(0) // Amount of fixed phase shift, -255 to 255
|
||||
) DCM0 (
|
||||
.CLK0(CLK0), // CLKOUT w/ 0 degree shift
|
||||
// .CLK2X(CLK_100), // 2 * CLK0 frequency
|
||||
// .CLKFX(CLKFX), // DCM CLK synthesis out (M/D)
|
||||
.CLKIN(CLKIN), // Clock input (from IBUFG, BUFG or DCM)
|
||||
.CLKFB(CLK0) // DCM clock feedback
|
||||
);
|
||||
|
||||
wire CLK_O = CLK0;
|
||||
reg RST_O = 1'b1;
|
||||
|
||||
wire [31:0] IADR_I;
|
||||
wire [31:0] INST_ADR_O;
|
||||
wire [7:0] INST_DAT_I;
|
||||
wire [31:2] CPU_ADR_O;
|
||||
wire [31:0] CPU_DAT_I;
|
||||
wire [31:0] CPU_DAT_O;
|
||||
wire [3:0] CPU_SEL_O;
|
||||
wire CPU_ACK_I;
|
||||
|
||||
StackCPU MyStackCPU (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.IRQ_I(IRQ_I),
|
||||
.IADR_I(IADR_I),
|
||||
.IACK_O(IACK_O),
|
||||
.INST_ADR_O(INST_ADR_O),
|
||||
.INST_DAT_I(INST_DAT_I),
|
||||
.INST_CYC_O(INST_CYC_O),
|
||||
.INST_STB_O(INST_STB_O),
|
||||
.INST_ACK_I(INST_ACK_I),
|
||||
.DATA_ADR_O(CPU_ADR_O),
|
||||
.DATA_DAT_I(CPU_DAT_I),
|
||||
.DATA_DAT_O(CPU_DAT_O),
|
||||
.DATA_CYC_O(CPU_CYC_O),
|
||||
.DATA_STB_O(CPU_STB_O),
|
||||
.DATA_WE_O(CPU_WE_O),
|
||||
.DATA_SEL_O(CPU_SEL_O),
|
||||
.DATA_ACK_I(CPU_ACK_I)
|
||||
);
|
||||
|
||||
// Bus arbiter master signals
|
||||
wire [31:2] DATA_ADR_O;
|
||||
reg [31:0] DATA_DAT_I;
|
||||
wire [31:0] DATA_DAT_O;
|
||||
wire [3:0] DATA_SEL_O;
|
||||
reg DATA_ACK_I;
|
||||
|
||||
`define SLV_PROGRAM_RAM 4'b0000
|
||||
`define SLV_SRAM 4'b0001
|
||||
`define SLV_IRQ_CTL 4'b0010
|
||||
`define SLV_DMA_CTL 4'b0011
|
||||
`define SLV_TIMER 4'b0100
|
||||
`define SLV_LED_SWITCH 4'b0101
|
||||
`define SLV_BTN_DISPLAY 4'b0110
|
||||
`define SLV_RS232 4'b0111
|
||||
`define SLV_UNUSED 4'b1111
|
||||
reg [3:0] SLAVE;
|
||||
|
||||
always @*
|
||||
begin
|
||||
/*
|
||||
casex (DATA_ADR_O)
|
||||
30'bXXXX_XXXX_XX00_XXXX_XXXX_XXXX_XXXX_XX: SLAVE <= `SLV_PROGRAM_RAM;
|
||||
30'bXXXX_XXXX_XX01_XXXX_XXXX_XXXX_XXXX_XX: SLAVE <= `SLV_SRAM;
|
||||
30'bXXXX_XXXX_XX11_XXXX_XXXX_XXXX_X0XX_XX: SLAVE <= `SLV_IRQ_CTL;
|
||||
30'bXXXX_XXXX_XX11_XXXX_XXXX_XXXX_X10X_XX: SLAVE <= `SLV_DMA_CTL;
|
||||
30'bXXXX_XXXX_XX11_XXXX_XXXX_XXXX_X110_XX: SLAVE <= `SLV_TIMER;
|
||||
30'bXXXX_XXXX_XX11_XXXX_XXXX_XXXX_X111_00: SLAVE <= `SLV_LED_SWITCH;
|
||||
30'bXXXX_XXXX_XX11_XXXX_XXXX_XXXX_X111_01: SLAVE <= `SLV_BTN_DISPLAY;
|
||||
30'bXXXX_XXXX_XX11_XXXX_XXXX_XXXX_X111_1X: SLAVE <= `SLV_RS232;
|
||||
default: SLAVE <= `SLV_UNUSED;
|
||||
endcase
|
||||
*/
|
||||
// Manually decode the above table, because xst appears to
|
||||
// attempt to expand it rather than ignore the 'X' bits.
|
||||
case (DATA_ADR_O[21:20])
|
||||
2'b00: SLAVE <= `SLV_PROGRAM_RAM;
|
||||
2'b01: SLAVE <= `SLV_SRAM;
|
||||
2'b10: SLAVE <= `SLV_UNUSED;
|
||||
2'b11:
|
||||
casex (DATA_ADR_O[6:2])
|
||||
5'b0XX_XX: SLAVE <= `SLV_IRQ_CTL;
|
||||
5'b10X_XX: SLAVE <= `SLV_DMA_CTL;
|
||||
5'b110_XX: SLAVE <= `SLV_TIMER;
|
||||
5'b111_00: SLAVE <= `SLV_LED_SWITCH;
|
||||
5'b111_01: SLAVE <= `SLV_BTN_DISPLAY;
|
||||
5'b111_1X: SLAVE <= `SLV_RS232;
|
||||
default: SLAVE <= `SLV_UNUSED;
|
||||
endcase
|
||||
endcase
|
||||
end
|
||||
|
||||
wire [31:0] DMA_CTL_DAT_O;
|
||||
wire [31:2] DMA_SRC_ADR_O;
|
||||
wire [31:0] DMA_SRC_DAT_I;
|
||||
wire [31:2] DMA_DST_ADR_O;
|
||||
wire [31:0] DMA_DST_DAT_O;
|
||||
|
||||
WB_DMA DMAController (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.IRQ_O(DMA_IRQ_O),
|
||||
.CTL_ADR_I(DATA_ADR_O[3:2]),
|
||||
.CTL_DAT_I(DATA_DAT_O),
|
||||
.CTL_DAT_O(DMA_CTL_DAT_O),
|
||||
.CTL_STB_I(DATA_STB_O & (SLAVE == `SLV_DMA_CTL)),
|
||||
.CTL_WE_I(DATA_WE_O),
|
||||
.CTL_ACK_O(DMA_CTL_ACK_O),
|
||||
.SRC_ADR_O(DMA_SRC_ADR_O),
|
||||
.SRC_DAT_I(DMA_SRC_DAT_I),
|
||||
.SRC_STB_O(DMA_SRC_STB_O),
|
||||
.SRC_WE_O(DMA_SRC_WE_O),
|
||||
.SRC_ACK_I(DMA_SRC_ACK_I),
|
||||
.DST_ADR_O(DMA_DST_ADR_O),
|
||||
.DST_DAT_O(DMA_DST_DAT_O),
|
||||
.DST_STB_O(DMA_DST_STB_O),
|
||||
.DST_WE_O(DMA_DST_WE_O),
|
||||
.DST_ACK_I(DMA_DST_ACK_I)
|
||||
);
|
||||
|
||||
wire [31:2] DMA_ADR_O;
|
||||
wire [31:0] DMA_DAT_O;
|
||||
wire [31:0] DMA_DAT_I;
|
||||
wire [3:0] DMA_SEL_O;
|
||||
wire DMA_ACK_I;
|
||||
|
||||
WB_ARB_2M DMAArbiter (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
|
||||
.M0_ADR_I(DMA_SRC_ADR_O),
|
||||
.M0_DAT_I(32'd0),
|
||||
.M0_DAT_O(DMA_SRC_DAT_I),
|
||||
.M0_LOCK_I(1'b0),
|
||||
.M0_CYC_I(DMA_SRC_STB_O),
|
||||
.M0_STB_I(DMA_SRC_STB_O),
|
||||
.M0_WE_I(DMA_SRC_WE_O),
|
||||
.M0_SEL_I(4'b1111),
|
||||
.M0_ACK_O(DMA_SRC_ACK_I),
|
||||
|
||||
.M1_ADR_I(DMA_DST_ADR_O),
|
||||
.M1_DAT_I(DMA_DST_DAT_O),
|
||||
.M1_LOCK_I(1'b0),
|
||||
.M1_CYC_I(DMA_DST_STB_O),
|
||||
.M1_STB_I(DMA_DST_STB_O),
|
||||
.M1_WE_I(DMA_DST_WE_O),
|
||||
.M1_SEL_I(4'b1111),
|
||||
.M1_ACK_O(DMA_DST_ACK_I),
|
||||
|
||||
.S_ADR_O(DMA_ADR_O),
|
||||
.S_DAT_O(DMA_DAT_O),
|
||||
.S_DAT_I(DMA_DAT_I),
|
||||
.S_CYC_O(DMA_CYC_O),
|
||||
.S_STB_O(DMA_STB_O),
|
||||
.S_WE_O(DMA_WE_O),
|
||||
.S_SEL_O(DMA_SEL_O),
|
||||
.S_ACK_I(DMA_ACK_I),
|
||||
.S_ERR_I(1'b0),
|
||||
.S_RTY_I(1'b0)
|
||||
);
|
||||
|
||||
WB_ARB_2M BusArbiter (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
|
||||
.M0_ADR_I(CPU_ADR_O),
|
||||
.M0_DAT_I(CPU_DAT_O),
|
||||
.M0_DAT_O(CPU_DAT_I),
|
||||
.M0_LOCK_I(1'b0),
|
||||
.M0_CYC_I(CPU_CYC_O),
|
||||
.M0_STB_I(CPU_STB_O),
|
||||
.M0_WE_I(CPU_WE_O),
|
||||
.M0_SEL_I(CPU_SEL_O),
|
||||
.M0_ACK_O(CPU_ACK_I),
|
||||
|
||||
.M1_ADR_I(DMA_ADR_O),
|
||||
.M1_DAT_I(DMA_DAT_O),
|
||||
.M1_DAT_O(DMA_DAT_I),
|
||||
.M1_LOCK_I(1'b0),
|
||||
.M1_CYC_I(DMA_CYC_O),
|
||||
.M1_STB_I(DMA_STB_O),
|
||||
.M1_WE_I(DMA_WE_O),
|
||||
.M1_SEL_I(DMA_SEL_O),
|
||||
.M1_ACK_O(DMA_ACK_I),
|
||||
|
||||
.S_ADR_O(DATA_ADR_O),
|
||||
.S_DAT_O(DATA_DAT_O),
|
||||
.S_DAT_I(DATA_DAT_I),
|
||||
.S_STB_O(DATA_STB_O),
|
||||
.S_WE_O(DATA_WE_O),
|
||||
.S_SEL_O(DATA_SEL_O),
|
||||
.S_ACK_I(DATA_ACK_I),
|
||||
.S_ERR_I(1'b0),
|
||||
.S_RTY_I(1'b0)
|
||||
);
|
||||
|
||||
wire [31:0] TIMER_DAT_O;
|
||||
|
||||
TIMER #(
|
||||
.INIT_RELOAD(32'd49999)
|
||||
) Timer (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.ADR_I(DATA_ADR_O[3:2]),
|
||||
.DAT_I(DATA_DAT_O),
|
||||
.DAT_O(TIMER_DAT_O),
|
||||
.STB_I(DATA_STB_O & (SLAVE == `SLV_TIMER)),
|
||||
.WE_I(DATA_WE_O),
|
||||
.ACK_O(TIMER_ACK_O),
|
||||
.IRQ_O(TIMER_IRQ_O)
|
||||
);
|
||||
|
||||
wire RS232_TX_FULL;
|
||||
wire RS232_RX_EMPTY;
|
||||
wire [31:0] IRQ_DAT_O;
|
||||
|
||||
IRQ_CTL InterruptController (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.IRQ_O(IRQ_I),
|
||||
.IADR_O(IADR_I),
|
||||
.IACK_I(IACK_O),
|
||||
.ADR_I(DATA_ADR_O[5:2]),
|
||||
.DAT_I(DATA_DAT_O),
|
||||
.DAT_O(IRQ_DAT_O),
|
||||
.STB_I(DATA_STB_O & (SLAVE == `SLV_IRQ_CTL)),
|
||||
.WE_I(DATA_WE_O),
|
||||
.SEL_I(DATA_SEL_O),
|
||||
.ACK_O(IRQ_ACK_O),
|
||||
.IRQ0(1'b0),
|
||||
.IRQ1(~RS232_RX_EMPTY),
|
||||
.IRQ2(DMA_IRQ_O),
|
||||
.IRQ3(~RS232_TX_FULL),
|
||||
.IRQ4(TIMER_IRQ_O),
|
||||
.IRQ5(1'b0),
|
||||
.IRQ6(1'b0),
|
||||
.IRQ7(1'b0)
|
||||
);
|
||||
|
||||
wire [31:0] PROGRAM_DAT_O;
|
||||
|
||||
ProgramRAM Program (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.INST_ADR_I(INST_ADR_O[12:0]),
|
||||
.INST_DAT_O(INST_DAT_I),
|
||||
.INST_STB_I(INST_STB_O),
|
||||
.INST_ACK_O(INST_ACK_I),
|
||||
.DATA_ADR_I(DATA_ADR_O[12:2]),
|
||||
.DATA_DAT_I(DATA_DAT_O),
|
||||
.DATA_DAT_O(PROGRAM_DAT_O),
|
||||
.DATA_STB_I(DATA_STB_O & (SLAVE == `SLV_PROGRAM_RAM)),
|
||||
.DATA_WE_I(DATA_WE_O),
|
||||
.DATA_SEL_I(DATA_SEL_O),
|
||||
.DATA_ACK_O(PROGRAM_ACK_O)
|
||||
);
|
||||
|
||||
wire [31:0] SRAM_DAT_O;
|
||||
|
||||
WB_SRAM WishboneSRAM (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.ADR_I(DATA_ADR_O[19:2]),
|
||||
.DAT_I(DATA_DAT_O),
|
||||
.DAT_O(SRAM_DAT_O),
|
||||
.STB_I(DATA_STB_O & (SLAVE == `SLV_SRAM)),
|
||||
.WE_I(DATA_WE_O),
|
||||
.SEL_I(DATA_SEL_O),
|
||||
.ACK_O(SRAM_ACK_O),
|
||||
.SRAM_ADR(SRAM_ADR),
|
||||
.SRAM_WE(SRAM_WE),
|
||||
.SRAM_OE(SRAM_OE),
|
||||
.SRAM_IO1(SRAM_IO1),
|
||||
.SRAM_CE1(SRAM_CE1),
|
||||
.SRAM_UB1(SRAM_UB1),
|
||||
.SRAM_LB1(SRAM_LB1),
|
||||
.SRAM_IO2(SRAM_IO2),
|
||||
.SRAM_CE2(SRAM_CE2),
|
||||
.SRAM_UB2(SRAM_UB2),
|
||||
.SRAM_LB2(SRAM_LB2)
|
||||
);
|
||||
|
||||
wire [31:0] RS232_DAT_O;
|
||||
|
||||
RS232 #(
|
||||
.CLOCK_DIV(434) // 115200 bps @ 50 MHz CLKIN
|
||||
) SerialInterface (
|
||||
.CLK_I(CLK_O),
|
||||
.RST_I(RST_O),
|
||||
.DAT_I(DATA_DAT_O),
|
||||
.DAT_O(RS232_DAT_O),
|
||||
.STB_I(DATA_STB_O & (SLAVE == `SLV_RS232)),
|
||||
.WE_I(DATA_WE_O),
|
||||
.SEL_I(DATA_SEL_O),
|
||||
.ACK_O(RS232_ACK_O),
|
||||
.TX_FULL(RS232_TX_FULL),
|
||||
.RX_EMPTY(RS232_RX_EMPTY),
|
||||
.RX(RX_A),
|
||||
.TX(TX_A)
|
||||
);
|
||||
|
||||
reg [7:0] SWITCH_R;
|
||||
reg [3:0] BTN_R;
|
||||
reg [7:0] LED = 8'h00;
|
||||
reg [19:0] DISPLAY = 20'h00000;
|
||||
|
||||
SevenSeg Display (
|
||||
.CLKIN(CLK_O),
|
||||
.INPUT(DISPLAY[15:0]),
|
||||
//.INPUT(INST_ADR_O[15:0]),
|
||||
//.INPUT(DATA_ADR_O[17:2]),
|
||||
.DP(DISPLAY[19:16]),
|
||||
.SEG(SEG),
|
||||
.ANODE(ANODE)
|
||||
);
|
||||
|
||||
always @*
|
||||
begin
|
||||
case (SLAVE)
|
||||
`SLV_PROGRAM_RAM: DATA_DAT_I <= PROGRAM_DAT_O;
|
||||
`SLV_SRAM: DATA_DAT_I <= SRAM_DAT_O;
|
||||
`SLV_IRQ_CTL: DATA_DAT_I <= IRQ_DAT_O;
|
||||
`SLV_DMA_CTL: DATA_DAT_I <= DMA_CTL_DAT_O;
|
||||
`SLV_TIMER: DATA_DAT_I <= TIMER_DAT_O;
|
||||
`SLV_LED_SWITCH: DATA_DAT_I <= { 24'h0, SWITCH_R };
|
||||
`SLV_BTN_DISPLAY: DATA_DAT_I <= { 4'h0, BTN_R, 4'h0, DISPLAY };
|
||||
`SLV_RS232: DATA_DAT_I <= RS232_DAT_O;
|
||||
default: DATA_DAT_I <= 32'hA5A5A5A5;
|
||||
endcase
|
||||
|
||||
case (SLAVE)
|
||||
`SLV_PROGRAM_RAM: DATA_ACK_I <= PROGRAM_ACK_O;
|
||||
`SLV_SRAM: DATA_ACK_I <= SRAM_ACK_O;
|
||||
`SLV_IRQ_CTL: DATA_ACK_I <= IRQ_ACK_O;
|
||||
`SLV_DMA_CTL: DATA_ACK_I <= DMA_CTL_ACK_O;
|
||||
`SLV_TIMER: DATA_ACK_I <= TIMER_ACK_O;
|
||||
`SLV_RS232: DATA_ACK_I <= RS232_ACK_O;
|
||||
default: DATA_ACK_I <= DATA_STB_O;
|
||||
endcase
|
||||
end
|
||||
|
||||
reg [15:0] RST_CNT = 16'hFFFF;
|
||||
|
||||
always @(posedge CLK_O)
|
||||
begin
|
||||
if (BTN_R[3] & ~&RST_CNT)
|
||||
RST_CNT <= RST_CNT + 16'd1;
|
||||
else if (|RST_CNT)
|
||||
RST_CNT <= RST_CNT - 16'd1;
|
||||
|
||||
if (RST_CNT == 16'hFFFF)
|
||||
RST_O <= 1'b1;
|
||||
else if (RST_CNT == 16'h0000)
|
||||
RST_O <= 1'b0;
|
||||
end
|
||||
|
||||
always @(posedge CLK_O)
|
||||
begin
|
||||
BTN_R <= BTN;
|
||||
SWITCH_R <= SWITCH;
|
||||
|
||||
if (DATA_STB_O & DATA_WE_O)
|
||||
begin
|
||||
case (SLAVE)
|
||||
`SLV_LED_SWITCH:
|
||||
LED <= DATA_DAT_O[7:0];
|
||||
`SLV_BTN_DISPLAY:
|
||||
begin
|
||||
if (DATA_SEL_O[2]) DISPLAY[19:16] <= DATA_DAT_O[19:16];
|
||||
if (DATA_SEL_O[1]) DISPLAY[15: 8] <= DATA_DAT_O[15: 8];
|
||||
if (DATA_SEL_O[0]) DISPLAY[ 7: 0] <= DATA_DAT_O[ 7: 0];
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
run -ifn toplevel.prj -ifmt mixed -top TopLevel
|
||||
-ofn toplevel.ngc -ofmt NGC -p xc3s200-ft256-4
|
||||
-opt_mode speed -opt_level 1 -slice_utilization_ratio 100
|
||||
-max_fanout 300 -rtlview yes
|
||||
Loading…
Reference in New Issue