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