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

Subversion Repositories softavrcore

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /softavrcore
    from Rev 1 to Rev 2
    Reverse comparison

Rev 1 → Rev 2

/trunk/build/Makefile
0,0 → 1,63
SHELL=/bin/sh
 
CC=avr-gcc
AS=avr-as
AR=avr-ar
OBJCOPY=avr-objcopy
OBJDUMP=avr-objdump
CHMOD=chmod
 
ARCH = avr2
ARCH_LIB = crt0.o
 
AFLAGS=-mmcu=$(ARCH)
#CFLAGS=-mmcu=$(ARCH) -D__COMPILING_AVR_LIBC__ -Wall -pedantic -O3
CFLAGS=-mmcu=$(ARCH) -D__COMPILING_AVR_LIBC__ -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wno-unused-function -O3
LDFLAGS=-mmcu=$(ARCH)
 
PMEM_DEPTH=10
PMEM_WORDS=$(shell echo $$((1<<$(PMEM_DEPTH))))
PMEM_SIZE=$(shell echo $$((2<<$(PMEM_DEPTH))))
 
PROGMEM=../util/progmem-ice40.sh
#PROGMEM=../util/progmem-generic.sh
 
.PHONY: all clean
 
TARGETS=main.disasm main.mem flash_array.v main.instr main.v
 
all: $(TARGETS)
 
crt0.o: crt0.s
$(AS) $(AFLAGS) -o crt0.o crt0.s
 
main.o: main.c
$(CC) $(CFLAGS) -c main.c
 
main.elf: main.o $(ARCH_LIB)
$(CC) $(LDFLAGS) -o main.elf main.o $(ARCH_LIB)
 
main.hex: main.elf
$(OBJCOPY) -j .text -j .data -O ihex main.elf main.hex
 
main.bin: main.elf
$(OBJCOPY) -j .text -j .data -O binary main.elf main.bin
$(CHMOD) -x main.bin
 
main.mem: main.bin
cat main.bin /dev/zero | head -c $(PMEM_SIZE) | hexdump -v -e '/2 "%.4x\n"' > main.mem
 
flash_array.v: main.mem
awk '{ printf("flash_array[%d]=16%ch%s;\n",n,39,$$1);n++; }' < main.mem > flash_array.v
 
main.disasm: main.elf
$(OBJDUMP) -s -m $(ARCH) -d main.elf > main.disasm
 
main.instr: main.disasm
expand < main.disasm | grep -v "file format" | awk '{ if ( substr($$1,length($$1))==":" ) print substr($$0,25,8); }' | sort | uniq | awk '{ print $$1; }' > main.instr
 
main.v: main.bin
$(PROGMEM) --depth $(PMEM_DEPTH) --name flash main.bin > main.v
 
clean:
rm -f $(TARGETS) *.o *.elf *.mem *.disasm *.hex *.bin
/trunk/build/crt0.s
0,0 → 1,99
;=============================================================================;
 
.set PINB, 0x16
 
.set VECTOR_SIZE, 2
.set VECTOR_WIDTH, 2
 
.set VECTOR_NUM, 1<<VECTOR_WIDTH
.set AVR_REG_SIZE, 0x0020
.set AVR_IO_SIZE, 0x0040
.set RAM_SIZE, 0x0200
 
;=============================================================================;
 
.set _RAMEND_ADDR, AVR_REG_SIZE + AVR_IO_SIZE + RAM_SIZE
.set _VECTORS_SIZE, VECTOR_SIZE * VECTOR_NUM
.set __stack_pointer, _RAMEND_ADDR - 1
.set AVR_STACK_POINTER_LO_ADDR, 0x3d
.set AVR_STACK_POINTER_HI_ADDR, 0x3e
.set AVR_SREG_ADDR, 0x3f
 
.macro XJMP name
.if (VECTOR_SIZE == 2)
rjmp \name
.elseif (VECTOR_SIZE == 4)
jmp \name
.else
nop
.endif
.endm
 
.macro XCALL name
.if (VECTOR_SIZE == 2)
rcall \name
.elseif (VECTOR_SIZE == 4)
call \name
.else
nop
.endif
.endm
.macro vector name
.if (. - __vectors < _VECTORS_SIZE)
.weak \name
.set \name, __bad_interrupt
XJMP \name
.endif
.endm
 
.section .vectors,"ax",@progbits
.global __vectors
.func __vectors
 
__vectors:
 
;in r16, PINB
;ldi r16, 0xC0
;out 0x04, r16
;rjmp __vectors
 
XJMP __init
vector __vector_1
vector __vector_2
vector __vector_3
vector __vector_4
vector __vector_5
vector __vector_6
vector __vector_7
vector __vector_8
vector __vector_9
vector __vector_10
vector __vector_11
vector __vector_12
vector __vector_13
vector __vector_14
vector __vector_15
.endfunc
 
.global __bad_interrupt
.func __bad_interrupt
__bad_interrupt:
.weak __vector_default
.set __vector_default, __bad_interrupt
rjmp __vector_default
.endfunc
 
__init:
 
eor r1, r1
out AVR_SREG_ADDR, r1
ldi r28,lo8(__stack_pointer)
out AVR_STACK_POINTER_LO_ADDR, r28
ldi r29,hi8(__stack_pointer)
out AVR_STACK_POINTER_HI_ADDR, r29
 
.section .init9,"ax",@progbits
 
XCALL main
XJMP exit
/trunk/build/main.c
0,0 → 1,195
#define F_CPU 12000000UL
 
#include <avr/cpufunc.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <util/delay.h>
#include <stdio.h>
 
/*****************************************************************************/
 
#define __IOR(x) (*(volatile uint8_t *)(0x20+(x)))
#define __IOW(x) (*(volatile uint16_t *)(0x20+(x)))
 
/*****************************************************************************/
 
 
#define IO_BASE_UART0 0x00
#define IO_BASE_PORTOUT0 0x04
#define IO_BASE_TIMER0 0x08
 
/* uart.h */
 
#define UDR0 __IOR(IO_BASE_UART0+0x00)
#define UCSRA0 __IOR(IO_BASE_UART0+0x01)
#define UCSRB0 __IOR(IO_BASE_UART0+0x02)
#define UBRR0 __IOR(IO_BASE_UART0+0x03)
 
/* UCSRA */
#define RXB8 0
#define PE 2
#define DOR 3
#define FE 4
#define UDRE 5
#define TXC 6
#define RXC 7
 
/* UCSRB */
#define TXB8 0
#define UCSZ 1
#define UPM0 2
#define UPM1 3
#define USBS 4
#define UDRIE 5
#define TXCIE 6
#define RXCIE 7
 
/* timer.h */
 
#define TCNT0 __IOW(IO_BASE_TIMER0+0x00)
#define TCR0 __IOR(IO_BASE_TIMER0+0x02)
#define TSR0 __IOR(IO_BASE_TIMER0+0x03)
 
#define TOF 7 /* timer overflow */
#define TOFIE 7 /* timer overflow interrupt enable */
#define TPRESC0 0 /* timer prescaler bit 0 */
#define TPRESC1 1 /* timer prescaler bit 1 */
 
/* port.h */
 
#define PORTOUT0 __IOR(IO_BASE_PORTOUT0+0x00)
 
/*****************************************************************************/
 
static int uart_putchar(char c, FILE *stream)
{
loop_until_bit_is_set(UCSRA0, UDRE);
UDR0 = c;
return(0);
}
 
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
 
/*****************************************************************************/
 
/* RXC */
ISR(_VECTOR(3))
{
uint8_t c;
c=UDR0;
if ( 'a' <= c && c <= 'z' ) c-=('a'-'A');
UDR0=c;
}
 
ISR(_VECTOR(1))
{
TCR0=TCR0;
PORTOUT0 ^= 0x02;
}
 
 
static inline void msleep(uint16_t msec)
{
while ( msec )
{ _delay_loop_2((uint32_t)F_CPU/4000UL);
msec--;
}
}
 
static void test_memory_buffer(void)
{
static char * string="0123456789";
uint8_t length=10,offset,cnt;
 
msleep(10);
 
offset=0;
cnt=0;
while ( 1 )
{ uint8_t c;
 
while ( ! (UCSRA0&(1<<RXC)) );
c=UDR0;
 
if ( c != 10 )
{ c=string[offset];
offset++;
if ( length==offset ) offset=0;
}
 
UDR0=c;
cnt++;
PORTOUT0=cnt&3;
};
 
}
 
static void test_uppercase(void)
{
while ( 1 )
{ uint8_t c;
while ( ! (UCSRA0&(1<<RXC)) );
c=UDR0;
if ( 'a' <= c && c <= 'z' ) c-=('a'-'A');
while ( ! (UCSRA0&(1<<UDRE)) );
UDR0=c;
};
}
 
static void test_printf(void)
{
int i;
 
stdout=&mystdout;
 
i=0;
PORTOUT0 = 0x90;
PORTOUT0 ^= 0x03;
 
while ( 1 )
{ PORTOUT0 ^= 0x03;
printf("[x] %d => %d\n",i,i*i);
msleep(1000);
i++;
}
}
 
void test_interrupt(void)
{
UCSRB0 |= (1<<RXCIE);
TCR0 = 0x02;
TCR0 |= (1<<TOFIE);
 
sei();
while ( 1 )
{ PORTOUT0 ^= 0x01;
msleep(500);
}
}
 
 
int main(void)
{
uint8_t c;
 
UBRR0 = 13-1;
 
test_printf();
test_interrupt();
test_uppercase();
test_memory_buffer();
 
c=0;
while ( 1 )
{ msleep(500);
PORTOUT0=c;
UDR0='a'+c;
c=(c+1)%4;
}
test_uppercase();
return(0);
}
 
/trunk/core/avr_core.v
0,0 → 1,1378
/*****************************************************************************/
/* avr_core.v */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* (c) 2019-2020; Andras Pal <apal@szofi.net> */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Portions of the code got inspiration from the Navre project */
/* (https://opencores.org/projects/navre) */
/*****************************************************************************/
 
`define AVR_200
//`define AVR_250
//`define AVR_310
//`define AVR_350
//`define AVR_400
//`define AVR_500
//`define AVR_510
 
`define AVR_INITIAL
 
/*****************************************************************************/
 
module avr_core
#( parameter pmem_width = 9, /* PMEM address bus width (16-bit instr) */
parameter dmem_width = 9, /* RAM address bus width (bytes) */
parameter interrupt = 1,
parameter intr_width = 2 /* number of interrupt vector bits */
)
( input clk,
input rst,
 
output pmem_ce,
output [pmem_width-1:0] pmem_a,
input [15:0] pmem_d,
 
output dmem_re,
output dmem_we,
output [dmem_width-1:0] dmem_a,
input [7:0] dmem_di,
output [7:0] dmem_do,
 
output io_re,
output io_we,
output [5:0] io_a,
input [7:0] io_di,
output [7:0] io_do,
 
input in_iflag,
input [intr_width-1:0] in_ivect
);
 
/*****************************************************************************/
 
/******************************************************************************
| avr2 avr25 avr31 avr35 avr4 avr5 avr51
-------------+-----------------------------------------------------------------
MOVW | X X X X X X
LPM Rd,Z(+) | X X X X X X
ELPM | X X
ELPM Rd,Z(+) | X
JMP/CALL | X X X X
SPM | X X X X X
MUL | X X X
******************************************************************************/
 
`ifdef AVR_250
`define AVR_HAVE_MOVW
`define AVR_HAVE_LPMZ
`define AVR_HAVE_SPM
`endif
 
`ifdef AVR_310
`define AVR_HAVE_MOVW
`define AVR_HAVE_LPMZ
`define AVR_HAVE_ELPM
`define AVR_HAVE_22BITPC
`endif
 
`ifdef AVR_350
`define AVR_HAVE_MOVW
`define AVR_HAVE_LPMZ
`define AVR_HAVE_22BITPC
`define AVR_HAVE_SPM
`endif
 
`ifdef AVR_400
`define AVR_HAVE_MOVW
`define AVR_HAVE_LPMZ
`define AVR_HAVE_SPM
`define AVR_HAVE_MUL
`endif
 
`ifdef AVR_500
`define AVR_HAVE_MOVW
`define AVR_HAVE_LPMZ
`define AVR_HAVE_22BITPC
`define AVR_HAVE_SPM
`define AVR_HAVE_MUL
`endif
 
`ifdef AVR_510
`define AVR_HAVE_MOVW
`define AVR_HAVE_LPMZ
`define AVR_HAVE_ELPM
`define AVR_HAVE_ELPMZ
`define AVR_HAVE_22BITPC
`define AVR_HAVE_SPM
`define AVR_HAVE_MUL
`endif
 
/*****************************************************************************/
 
localparam MEM_OFFSET = 96;
 
/*****************************************************************************/
 
`ifdef AVR_INITIAL
localparam STATE_INITIAL = 4'd0;
localparam STATE_STALL = 4'd1;
`else
localparam STATE_STALL = 4'd0;
`endif
localparam STATE_NORMAL = 4'd2;
localparam STATE_TWOWORD = 4'd3;
localparam STATE_SKIP = 4'd4;
localparam STATE_LD = 4'd5;
localparam STATE_CALL = 4'd6;
localparam STATE_RET = 4'd7;
localparam STATE_RET2 = 4'd8;
localparam STATE_LPM = 4'd9;
localparam STATE_LPM2 = 4'd10;
localparam STATE_ADIW = 4'd11;
localparam STATE_IO_BIT = 4'd12;
localparam STATE_MUL = 4'd13;
localparam STATE_IN = 4'd14;
 
/*****************************************************************************/
 
/* CPU core state registers: */
reg [pmem_width-1:0] PC; /* <= 0 */
reg [3:0] state; /* <= 0: hence, STALL state should be zero! */
 
wire [15:0] INSTR;
reg [15:0] PREVI;
reg [7:0] GPR[0:31];
 
`ifdef AVR_INITIAL
`ifdef SIMULATOR
localparam init_depth = 3;
`else
localparam init_depth = 8;
`endif
reg [init_depth-1:0] init_count;
`endif
 
`ifdef SIMULATOR
integer i;
initial begin
for ( i=0;i<32;i=i+1)
GPR[i] <= 8'hA0 + i;
end
`endif
 
wire [15:0] RX = { GPR[27], GPR[26] };
wire [15:0] RY = { GPR[29], GPR[28] };
wire [15:0] RZ = { GPR[31], GPR[30] };
 
reg I, T, H, S, V, N, Z, C; /* initialized as <= 0 */
 
wire [7:0] SREG = { I, T, H, S, V, N, Z, C };
 
reg [15:0] SP; /* initialized as <= 0 */
 
 
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
reg nI, nT, nH, nS, nV, nN, nZ, nC;
wire [7:0] nSREG = { nI, nT, nH, nS, nV, nN, nZ, nC };
 
reg [7:0] R; /* generic result for writeback */
reg [7:0] R_high; /* result for 1-word writeback - high byte */
 
wire [15:0] RX_inc_dec = (INSTR[0] ? RX + 1 : RX - 1);
wire [15:0] RY_inc_dec = (INSTR[0] ? RY + 1 : RY - 1);
wire [15:0] RZ_inc_dec = (INSTR[0] ? RZ + 1 : RZ - 1);
wire [15:0] RZ_inc = (INSTR[0] ? RZ + 1 : RZ );
 
/* arithmetic and logic operators, followed by an 8-bit immediate operand: */
/* only these instruction imply destination registers r16 ... r31 */
wire immediate = (INSTR[15:14] == 2'b01 ) | /* ANDI, ORI, SBCI, SUBI */
(INSTR[15:12] == 4'b0011) | /* CPI */
(INSTR[15:12] == 4'b1110); /* LDI */
 
wire [4:0] Rd_normal = { immediate | INSTR[8], INSTR[7:4] };
 
wire [4:0] Rd = Rd_normal;
 
wire [4:0] Rd_prev = PREVI[8:4];
wire [4:0] Rr = { INSTR[9], INSTR[3:0] };
wire [1:0] Rd16 = INSTR[5:4];
wire [1:0] Rp16 = PREVI[5:4];
wire [7:0] GPR_Rd = GPR[Rd];
wire [2:0] b = INSTR[2:0];
wire GPR_Rd_b = GPR_Rd[b];
wire [7:0] GPR_Rr = GPR[Rr];
wire [3:0] RD16 = INSTR[7:4];
wire [3:0] RR16 = INSTR[3:0];
 
/* used by: ANDI, ORI, SBCI, SUBI, CPI, LDI (i.e. where immediate == 1'b1): */
wire [7:0] K = { INSTR[11:8], INSTR[3:0] };
/* used by: LDD Rd, Y+q; LDD RD, Z+q; STD Y+q, Rd; STD Z+q, Rd: */
wire [5:0] q = { INSTR[13], INSTR[11:10], INSTR[2:0] };
/* used by: ADIW, SBIW: */
wire [5:0] K16 = { INSTR[7:6], INSTR[3:0] };
 
wire two_word_lds_sts = ((INSTR[15:10]==6'b100100) & (INSTR[3:0]==4'b0000));
 
`ifdef AVR_HAVE_22BITPC
/* this is for avr3 (avr31, avr35) and avr5 (avr51): */
wire two_word_jmp_call = ((INSTR[15:9]==7'b1001010) & (INSTR[3:2]==2'b11));
wire two_word_instr = two_word_lds_sts | two_word_jmp_call;
`else
/* otherwise (avr2, avr25 and avr4): */
wire two_word_instr = two_word_lds_sts;
`endif
 
`ifdef AVR_HAVE_MUL
wire [4:0] Rd_mul = INSTR[15] ? INSTR[8:4] : ~INSTR[8] ? { 1'b1, INSTR[7:4] } : { 2'b10, INSTR[6:4] };
wire [4:0] Rr_mul = INSTR[15] ? Rr : ~INSTR[8] ? { 1'b1, INSTR[3:0] } : { 2'b10, INSTR[2:0] };
wire [7:0] GPR_Rd_mul = GPR[Rd_mul];
wire [7:0] GPR_Rr_mul = GPR[Rr_mul];
reg [7:0] mul_rd;
reg [7:0] mul_rr;
reg [15:0] product;
/* FMUL, FMULS, FMULSU: */
wire fmulxx = ~INSTR[15] & (INSTR[3] | INSTR[7]);
/* MULS, FMULS: */
wire xmulsx = ~INSTR[15] & (~INSTR[8] | ({INSTR[7],INSTR[3]} == 2'b10));
/* MULS, MULSU, FMULS, FMULSU: */
wire xmulsu = ~INSTR[15] & (~INSTR[8] | ({INSTR[7],INSTR[3]} != 2'b01));
reg [2:0] mul_type; /* = { fmulxx, xmulsx, xmulsu }; */
`endif
 
/* stage2 temporary registers: */
 
reg [2:0] writeback;
reg change_z;
reg update_nsz;
reg [pmem_width-1:0] pc_next;
reg [15:0] sp_next;
reg sp_update;
 
reg [4:0] Rd_ld_save;
reg lpm_z_low;
 
localparam WRITEBACK_NONE = 3'd0;
localparam WRITEBACK_GPR = 3'd1;
localparam WRITEBACK_ZINC = 3'd4;
localparam WRITEBACK_ZY = 3'd5;
localparam WRITEBACK_X = 3'd6;
 
reg [3:0] next_state;
 
reg [15:0] pc_call_next;
reg [15:0] pc_call;
 
wire [15:0] pc_full = { {(16-pmem_width){1'b0}}, PC };
wire [15:0] pc_full_dec = { {(16-pmem_width){1'b0}}, PC - 1'b1 };
 
/* data memory interface: */
reg [15:0] d_addr;
reg d_read;
reg d_write;
reg [7:0] d_out;
 
/* interrupts: */
wire is_tail_reti;
wire is_interrupt;
 
reg iflag;
reg [intr_width-1:0] ivect;
 
generate
if ( interrupt ) begin
assign is_tail_reti = INSTR[4] & iflag;
assign is_interrupt = I & iflag & (state==STATE_NORMAL);
end else begin
assign is_tail_reti = 0;
assign is_interrupt = 0;
end
endgenerate
 
/* Instructions performing memory I/O via the dmem_* bus: */
 
// 16'b10q0_qq0d_dddd_0qqq LD Rd, Z+q
// 16'b10q0_qq0d_dddd_1qqq LD Rd, Y+q
// 16'b10q0_qq1d_dddd_0qqq ST Z+q, Rd
// 16'b10q0_qq1d_dddd_1qqq ST Y+q, Rd
// 16'b1001_000d_dddd_0001 LD Rd, Z++
// 16'b1001_000d_dddd_1001 LD Rd, Y++
// 16'b1001_001d_dddd_0001 ST Z++, Rd
// 16'b1001_001d_dddd_1001 ST Y++, Rd
// 16'b1001_000d_dddd_0010 LD Rd, --Z
// 16'b1001_000d_dddd_1010 LD Rd, --Y
// 16'b1001_001d_dddd_0010 ST --Z, Rd
// 16'b1001_001d_dddd_1010 ST --Y, Rd
// 16'b1001_000d_dddd_1100 LD Rd, X
// 16'b1001_000d_dddd_1101 LD Rd, X++
// 16'b1001_000d_dddd_1110 LD Rd, --X
// 16'b1001_001d_dddd_1100 ST X, Rd
// 16'b1001_001d_dddd_1101 ST X++, Rd
// 16'b1001_001d_dddd_1110 ST --X, Rd
// 16'b1001_000d_dddd_1111 POP Rd == LD Rd, ++SP
// 16'b1001_001d_dddd_1111 PUSH Rd == ST SP--, Rd
 
// 16'b1001_000d_dddd_1101 LD Rd, X++
// 16'b1001_000d_dddd_1110 LD Rd, --X
// 16'b1001_001d_dddd_1101 ST X++, Rd
// 16'b1001_001d_dddd_1110 ST --X, Rd
 
// 16'b1001_000d_dddd_1001 LD Rd, Y++
// 16'b1001_000d_dddd_1010 LD Rd, --Y
// 16'b1001_001d_dddd_1001 ST Y++, Rd
// 16'b1001_001d_dddd_1010 ST --Y, Rd
 
// 16'b1001_000d_dddd_0001 LD Rd, Z++
// 16'b1001_000d_dddd_0010 LD Rd, --Z
// 16'b1001_001d_dddd_0001 ST Z++, Rd
// 16'b1001_001d_dddd_0010 ST --Z, Rd
 
// 16'b1001_000d_dddd_01x1 LPM Rd, Z++
 
// INSTR[15:10] == 6'b100100
// X increased/decreased: INSTR[3:2] == 2'b11
// Y increased/decreased: INSTR[3:2] == 2'b10
// Z increased/decreased: INSTR[3:2] == 2'b00
// Z increased INSTR[3:2] == 2'b01
 
/* setting up memory interface lines (d_addr, d_out, d_read and d_write): */
 
always @(*) begin
 
d_out = 0;
d_addr = 0;
d_read = 0;
d_write = 0;
 
case (state)
 
STATE_NORMAL: begin
 
casex (INSTR)
 
16'b10x0_xx0x_xxxx_xxxx: begin
/* LD Rd, Z+q */
/* LD Rd, Y+q */
d_addr = (~INSTR[3]?RZ:RY) + q;
d_read = 1;
end
 
16'b10x0_xx1x_xxxx_xxxx: begin
/* ST Z+q, Rd */
/* ST Y+q, Rd */
d_addr = (~INSTR[3]?RZ:RY) + q;
d_out = GPR_Rd;
d_write = 1;
end
 
16'b1001_000x_xxxx_x001: begin
/* LD Rd, Z++ */
/* LD Rd, Y++ */
d_addr = (~INSTR[3]?RZ:RY);
d_read = 1;
end
 
16'b1001_001x_xxxx_x001: begin
/* ST Z++, Rd */
/* ST Y++, Rd */
d_addr = (~INSTR[3]?RZ:RY);
d_out = GPR_Rd;
d_write = 1;
end
 
16'b1001_000x_xxxx_x010: begin
/* LD Rd, --Z */
/* LD Rd, --Y */
d_addr = (~INSTR[3]?RZ:RY) - 1;
d_read = 1;
end
 
16'b1001_001x_xxxx_x010: begin
/* ST --Z, Rd */
/* ST --Y, Rd */
d_addr = (~INSTR[3]?RZ:RY) - 1;
d_out = GPR_Rd;
d_write = 1;
end
 
16'b1001_000x_xxxx_110x: begin
/* LD Rd, X */
/* LD Rd, X++ */
d_addr = RX;
d_read = 1;
end
16'b1001_000x_xxxx_1110: begin
/* LD Rd, --X */
d_addr = RX - 1;
d_read = 1;
end
 
16'b1001_001x_xxxx_110x: begin
/* ST X, Rd */
/* ST X++, Rd */
d_addr = RX;
d_out = GPR_Rd;
d_write = 1;
end
 
16'b1001_001x_xxxx_1110: begin
/* ST --X, Rd */
d_addr = RX - 1;
d_out = GPR_Rd;
d_write = 1;
end
 
16'b1001_000x_xxxx_1111: begin
/* POP Rd -- LD Rd, ++SP */
d_addr = SP + 1;
d_read = 1;
end
 
16'b1001_001x_xxxx_1111: begin
/* PUSH Rd -- ST SP--, Rd */
d_addr = SP;
d_out = GPR_Rd;
d_write = 1;
end
 
16'b1101_xxxx_xxxx_xxxx,
16'b1001_0101_0000_1001: begin
/* RCALL */
/* ICALL */
d_addr = SP;
d_out = pc_full[15:8];
d_write = 1;
end
 
16'b1001_0101_000x_1000: begin
/* RET, RETI */
d_addr = SP + 1;
d_read = 1;
end
 
endcase
 
if (is_interrupt) begin
d_addr = SP;
d_out = pc_full_dec[15:8];
d_write = 1;
end
 
end
 
STATE_TWOWORD: begin
casex(PREVI)
 
16'b1001_000x_xxxx_0000: begin
/* LDS Rd, 0xXXXX */
d_addr = INSTR;
d_read = 1;
end
 
16'b1001_001x_xxxx_0000: begin
/* STS 0xXXXX, Rd */
d_addr = INSTR;
d_out = GPR[Rd_prev];
d_write = 1;
end
 
`ifdef AVR_HAVE_22BITPC
16'b1001_010x_xxxx_111x: begin
/* CALL k */
d_addr = SP;
d_out = pc_full[15:8];
d_write = 1;
end
`endif
 
endcase
 
end
 
STATE_CALL: begin
/* RCALL */
/* ICALL */
d_addr = SP;
d_out = pc_full[7:0];
d_write = 1;
end
 
STATE_RET: begin
d_addr = SP + 1;
d_read = 1;
end
 
endcase
end
 
assign dmem_a = d_addr[dmem_width-1:0] - MEM_OFFSET;
assign dmem_re = d_read;
assign dmem_we = d_write;
assign dmem_do = d_out;
 
/* IN/OUT assignments: */
 
/* used by: IN, OUT, SBIC, SBIS, CBI, SBI: */
// 16'b1011_0aad_dddd_aaaa: /* IN */
// 16'b1011_1aad_dddd_aaaa: /* OUT */
// 16'b1001_1000_aaaa_abbb: /* CBI */
// 16'b1001_1010_aaaa_abbb: /* SBI */
// 16'b1001_1001_aaaa_abbb: /* SBIC */
// 16'b1001_1011_aaaa_abbb: /* SBIS */
 
reg [7:0] Rio;
 
wire [5:0] a = INSTR[13] ? {INSTR[10:9], INSTR[3:0]} : {1'b0, INSTR[7:3]};
wire io_act = (INSTR[15:12]==4'b1011) & (state == STATE_NORMAL);
assign io_a = (state == STATE_IO_BIT ? {1'b0, PREVI[7:3]} : a);
assign io_do = (state == STATE_IO_BIT ? Rio : GPR_Rd);
assign io_re = (io_act & (INSTR[11]==1'b0)) | ((state == STATE_NORMAL) & (INSTR[15:10]==6'b100110));
assign io_we = (io_act & (INSTR[11]==1'b1)) | (state == STATE_IO_BIT);
 
 
wire [7:0] Rin = (a==61?(SP[7:0]):(a==62?(SP[15:8]):(a==63?SREG:io_di)));
 
/*
reg [7:0] Rin;
always @(*) begin
if (a==6'b111101) begin
Rin = SP[7:0];
end else if (a==6'b111110) begin
Rin = SP[15:8];
end else if (a==6'b111111) begin
Rin = SREG;
end else begin
Rin = io_di;
end
end
*/
 
/* CPU instruction pipeline, stage 1: */
 
assign pmem_ce = 1'b1;
assign pmem_a = PC;
/* always @(posedge clk) pmem_d <= FLASH[pmem_a]; */
assign INSTR = pmem_d;
 
always @(posedge clk) begin
 
PREVI <= INSTR;
 
iflag <= in_iflag;
ivect <= in_ivect;
 
end /* always @(posedge clk) */
 
/* CPU instruction pipeline, stage 2: */
 
always @(*) begin
 
R = 0;
R_high = 0;
 
writeback = WRITEBACK_NONE ;
change_z = 1;
update_nsz = 0;
 
next_state = STATE_NORMAL;
pc_next = PC;
sp_next = SP;
sp_update = 0;
 
pc_call_next = 0;
 
{ nI, nT, nH, nS, nV, nN, nZ, nC } = SREG;
 
case(state)
 
STATE_NORMAL: begin
 
casex(INSTR)
 
`ifdef AVR_HAVE_MOVW
16'b0000_0001_xxxx_xxxx: begin
R = GPR[2*RR16+0];
R_high = GPR[2*RR16+1];
pc_next = PC + 1;
end
`endif
 
`ifdef AVR_HAVE_MUL
16'b1001_11xx_xxxx_xxxx,
16'b0000_001x_xxxx_xxxx: begin
/* MUL */
/* MULS */
/* MULSU */
/* FMUL */
/* FMULS */
/* FMULSU */
next_state = STATE_MUL;
end
`endif
 
16'b000x_10xx_xxxx_xxxx, /* subtract */
16'b000x_01xx_xxxx_xxxx: /* compare */ begin
/* SUB - SBC / CP - CPC */
{nC, R} = GPR_Rd - GPR_Rr - (~INSTR[12] & C);
nH = (~GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & R[3])|(R[3] & ~GPR_Rd[3]);
nV = (GPR_Rd[7] & ~GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & GPR_Rr[7] & R[7]);
update_nsz = 1;
if (~INSTR[12])
change_z = 1'b0;
if (INSTR[11])
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b000x_11xx_xxxx_xxxx: begin
/* ADD - ADC */
{nC, R} = GPR_Rd + GPR_Rr + (INSTR[12] & C);
nH = (GPR_Rd[3] & GPR_Rr[3])|(GPR_Rr[3] & ~R[3])|(~R[3] & GPR_Rd[3]);
nV = (GPR_Rd[7] & GPR_Rr[7] & ~R[7])|(~GPR_Rd[7] & ~GPR_Rr[7] & R[7]);
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b010x_xxxx_xxxx_xxxx, /* subtract */
16'b0011_xxxx_xxxx_xxxx: /* compare */ begin
/* SUBI - SBCI / CPI */
{nC, R} = GPR_Rd - K - (~INSTR[12] & C);
nH = (~GPR_Rd[3] & K[3])|(K[3] & R[3])|(R[3] & ~GPR_Rd[3]);
nV = (GPR_Rd[7] & ~K[7] & ~R[7])|(~GPR_Rd[7] & K[7] & R[7]);
update_nsz = 1;
if (~INSTR[12])
change_z = 1'b0;
if (INSTR[14])
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
 
16'b0111_xxxx_xxxx_xxxx: begin
/* ANDI Rd, K; */
R = GPR_Rd & K;
nV = 1'b0;
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
 
16'b0110_xxxx_xxxx_xxxx: begin
/* ORI Rd, K; */
R = GPR_Rd | K;
nV = 1'b0;
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
 
16'b0010_00xx_xxxx_xxxx: begin
/* AND */
R = GPR_Rd & GPR_Rr;
nV = 1'b0;
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b0010_01xx_xxxx_xxxx: begin
/* EOR */
R = GPR_Rd ^ GPR_Rr;
nV = 1'b0;
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b0010_10xx_xxxx_xxxx: begin
/* OR */
R = GPR_Rd | GPR_Rr;
nV = 1'b0;
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b0010_11xx_xxxx_xxxx: begin
/* MOV */
R = GPR_Rr;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_0000: begin
/* COM */
R = ~GPR_Rd;
nV = 1'b0;
nC = 1'b1;
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_0001: begin
/* NEG */
{nC, R} = 8'h00 - GPR_Rd;
nH = R[3] | GPR_Rd[3];
nV = (R == 8'h80);
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_0011: begin
/* INC */
R = GPR_Rd + 8'd1;
nV = (R == 8'h80);
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_1010: begin
/* DEC */
R = GPR_Rd - 8'd1;
nV = (R == 8'h7f);
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_011x: begin
/* LSR - ROR */
R = {INSTR[0] & C, GPR_Rd[7:1]};
nC = GPR_Rd[0];
nV = R[7] ^ GPR_Rd[0];
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_0101: begin
/* ASR */
R = {GPR_Rd[7], GPR_Rd[7:1]};
nC = GPR_Rd[0];
nV = R[7] ^ GPR_Rd[0];
update_nsz = 1;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_010x_xxxx_0010: begin
/* SWAP */
R = {GPR_Rd[3:0], GPR_Rd[7:4]};
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1001_0100_xxxx_1000: begin
/* BSET - BCLR */
case(INSTR[7:4])
4'b0000: nC = 1'b1;
4'b0001: nZ = 1'b1;
4'b0010: nN = 1'b1;
4'b0011: nV = 1'b1;
4'b0100: nS = 1'b1;
4'b0101: nH = 1'b1;
4'b0110: nT = 1'b1;
4'b0111: nI = 1'b1;
4'b1000: nC = 1'b0;
4'b1001: nZ = 1'b0;
4'b1010: nN = 1'b0;
4'b1011: nV = 1'b0;
4'b1100: nS = 1'b0;
4'b1101: nH = 1'b0;
4'b1110: nT = 1'b0;
4'b1111: nI = 1'b0;
endcase
pc_next = PC + 1;
end
 
16'b1001_011x_xxxx_xxxx: begin
/* SBIW */
/* ADIW */
if(INSTR[8]) begin /* SBIW */
{nC, R} = GPR[24+2*Rd16] - K16;
end else begin /* ADIW */
{nC, R} = GPR[24+2*Rd16] + K16;
end
nZ = (R==0);
next_state = STATE_ADIW;
end
 
16'b1001_00xx_xxxx_0000: begin
/* LDS Rd, 0xXXXX */
/* STS 0xXXXX, Rd */
pc_next = PC + 1;
next_state = STATE_TWOWORD;
end
 
`ifdef AVR_HAVE_22BITPC
16'b1001_010x_xxxx_11xx: begin
/* JMP k */
/* CALL k */
pc_next = PC + 1;
next_state = STATE_TWOWORD;
end
`endif
 
16'b10x0_xx0x_xxxx_xxxx: begin
/* LD Rd, Z+q; */
/* LD Rd, Y+q; */
next_state = STATE_LD;
end
 
16'b10x0_xx1x_xxxx_xxxx: begin
/* ST Z+q, Rd */
/* ST Y+q, Rd */
pc_next = PC + 1;
end
 
16'b1001_000x_xxxx_x001: begin
/* LD Rd, Z++ */
/* LD Rd, Y++ */
next_state = STATE_LD;
/* save dest register for the next cycle: */
writeback = WRITEBACK_ZY;
end
 
16'b1001_001x_xxxx_x001: begin
/* ST Z++, Rd */
/* ST Y++, Rd */
pc_next = PC + 1;
writeback = WRITEBACK_ZY;
end
 
16'b1001_000x_xxxx_x010: begin
/* LD Rd, --Z */
/* LD Rd, --Y */
next_state = STATE_LD;
/* save dest register for the next cycle: */
writeback = WRITEBACK_ZY;
end
 
16'b1001_001x_xxxx_x010: begin
/* ST --Z, Rd */
/* ST --Y, Rd */
pc_next = PC + 1;
writeback = WRITEBACK_ZY;
end
 
16'b1001_000x_xxxx_1100: begin
/* LD Rd, X */
next_state = STATE_LD;
end
 
16'b1001_001x_xxxx_1100: begin
/* ST X, Rd */
pc_next = PC + 1;
end
 
16'b1001_000x_xxxx_1101: begin
/* LD Rd, X++ */
writeback = WRITEBACK_X;
next_state = STATE_LD;
end
 
16'b1001_001x_xxxx_1101: begin
/* ST X++, Rd */
writeback = WRITEBACK_X;
pc_next = PC + 1;
end
 
16'b1001_000x_xxxx_1110: begin
/* LD Rd, --X */
writeback = WRITEBACK_X;
next_state = STATE_LD;
end
 
16'b1001_001x_xxxx_1110: begin
/* ST --X, Rd */
writeback = WRITEBACK_X;
pc_next = PC + 1;
end
 
16'b1001_000x_xxxx_1111: begin
/* POP Rd */ /* LD Rd, ++SP */
sp_next = SP + 1;
sp_update = 1;
next_state = STATE_LD;
end
 
16'b1001_001x_xxxx_1111: begin
/* PUSH Rd */ /* ST SP--, Rd */
sp_next = SP - 1;
sp_update = 1;
next_state = STATE_STALL;
end
 
16'b1100_xxxx_xxxx_xxxx: begin
/* RJMP */
next_state = STATE_STALL;
pc_next = PC + { {4{INSTR[11]}}, INSTR[11:0] };
end
16'b1001_0100_0000_1001: begin
/* IJMP */
next_state = STATE_STALL;
pc_next = RZ;
end
 
16'b1101_xxxx_xxxx_xxxx: begin
/* RCALL */
pc_call_next = pc_full + { {4{INSTR[11]}}, INSTR[11:0] };
sp_next = SP - 1;
sp_update = 1;
next_state = STATE_CALL;
end
16'b1001_0101_0000_1001: begin
/* ICALL */
pc_call_next = RZ;
sp_next = SP - 1;
sp_update = 1;
next_state = STATE_CALL;
end
 
16'b1001_0101_0000_1000, /* INSTR: 0x9508 */
16'b1001_0101_0001_1000: begin /* INSTR: 0x9518 */
/* RET */
/* RETI */
 
if ( is_tail_reti ) begin
// `RETI` is equivalent to `JMP ivect` if
// there is a pending interrupt:
next_state = STATE_STALL;
pc_next = ivect;
end else begin
// Otherwise, RETI and RET is the same...
next_state = STATE_RET;
sp_next = SP + 1;
sp_update = 1;
// ... besides that RETI sets the I flag:
if (INSTR[4])
nI = 1'b1;
 
end
 
end
 
16'b1001_0101_110x_1000: begin
/* LPM */
/* ELPM */
pc_call_next = PC;
pc_next = RZ[pmem_width:1];
next_state = STATE_LPM;
end
 
// `ifdef AVR_HAVE_SPM
// 16'b1001_0101_111x_1000: begin
// /* SPM Z */
// /* SPM Z+ */
// pc_call_next = PC;
// pc_next = RZ[pmem_width:1];
// next_state = STATE_LPM;
// end
// `endif
 
`ifdef AVR_HAVE_LPMZ
16'b1001_000x_xxxx_01xx: begin
/* LPM Rd, Z */
/* LPM Rd, Z++ */
/* ELPM Rd, Z */
/* ELPM Rd, Z++ */
pc_call_next = PC;
pc_next = RZ[pmem_width:1];
next_state = STATE_LPM;
writeback = WRITEBACK_ZINC;
end
`endif
 
16'b1111_0xxx_xxxx_xxxx: begin
/* BRxS - BRxC */
if (SREG[b] ^ INSTR[10]) begin
next_state = STATE_STALL;
pc_next = PC + { {9{INSTR[9]}}, INSTR[9:3] };
end else begin
pc_next = PC + 1;
end
end
16'b1111_11xx_xxxx_0xxx: begin
/* SBRC */
/* SBRS */
if (GPR_Rd_b == INSTR[9]) begin
next_state = STATE_SKIP;
end
pc_next = PC + 1;
end
16'b1001_10x0_xxxx_xxxx: begin
/* CBI */
/* SBI */
next_state = STATE_IO_BIT;
end
16'b1001_10x1_xxxx_xxxx: begin
/* SBIC */
/* SBIS */
if (Rin[b]==INSTR[9]) begin
next_state = STATE_SKIP;
end
pc_next = PC + 1;
end
16'b0001_00xx_xxxx_xxxx: begin
/* CPSE */
if (GPR_Rd == GPR_Rr) begin
next_state = STATE_SKIP;
end
pc_next = PC + 1;
end
16'b1110_xxxx_xxxx_xxxx: begin
/* LDI */
R = K;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1111_10xx_xxxx_0xxx: begin
/* BST */
/* BLD */
if (INSTR[9]) begin /* BST */
nT = GPR_Rd_b;
end else begin /* BLD */
case (b)
3'd0: R = { GPR_Rd[7:1], T };
3'd1: R = { GPR_Rd[7:2], T, GPR_Rd[0] };
3'd2: R = { GPR_Rd[7:3], T, GPR_Rd[1:0] };
3'd3: R = { GPR_Rd[7:4], T, GPR_Rd[2:0] };
3'd4: R = { GPR_Rd[7:5], T, GPR_Rd[3:0] };
3'd5: R = { GPR_Rd[7:6], T, GPR_Rd[4:0] };
3'd6: R = { GPR_Rd[7], T, GPR_Rd[5:0] };
3'd7: R = { T, GPR_Rd[6:0] };
endcase
writeback = WRITEBACK_GPR;
end
pc_next = PC + 1;
end
16'b1011_0xxx_xxxx_xxxx: begin
/* IN */
R = Rin;
writeback = WRITEBACK_GPR;
pc_next = PC + 1;
end
16'b1011_1xxx_xxxx_xxxx: begin
/* OUT */
if (a==6'b111101) begin /* SPL */
sp_next[7:0] = GPR_Rd;
sp_update = 1;
end else if (a==6'b111110) begin /* SPH */
sp_next[15:8] = GPR_Rd;
sp_update = 1;
end else if (a==6'b111111) begin /* SREG */
{ nI, nT, nH, nS, nV, nN, nZ, nC } = GPR_Rd;
end
// in all other cases, the data flow is handled
// by the IN/OUT persistent assignments (see earlier)
pc_next = PC + 1;
end
 
default:
pc_next = PC + 1;
endcase
if (update_nsz) begin
nN = R[7];
nS = nN ^ nV;
nZ = (R == 8'h00) & (change_z|Z);
end
 
// `ifdef AVR_INTERRUPT
if (is_interrupt) begin
// An interrupt is equivalent to a CALL, however,
// the actual program counter needed to be saved, not
// the PC corresponding to the following instruction.
// Due to the two-stage pipeline, the current
// instruction is PC - 1, and not PC:
writeback = 0;
pc_call_next = ivect;
sp_next = SP - 1;
sp_update = 1;
next_state = STATE_CALL;
pc_next = PC - 1;
nI = 0;
end
// `endif
 
end /* STATE_NORMAL */
STATE_TWOWORD: begin
casex(PREVI)
 
16'b1001_000x_xxxx_0000: begin
/* LDS Rd, 0xXXXX */
next_state = STATE_LD;
end
 
16'b1001_001x_xxxx_0000: begin
/* STS 0xXXXX, Rd */
pc_next = PC + 1;
end
 
`ifdef AVR_HAVE_22BITPC
16'b1001_010x_xxxx_110x: begin
/* JMP K */
next_state = STATE_STALL;
pc_next = INSTR;
end
16'b1001_010x_xxxx_111x: begin
/* CALL K */
pc_call_next = INSTR;
sp_next = SP - 1;
sp_update = 1;
next_state = STATE_CALL;
end
`endif
 
default:
pc_next = PC + 1;
 
endcase
 
end /* STATE_TWOWORD */
 
STATE_STALL: begin
pc_next = PC + 1;
next_state = STATE_NORMAL;
end /* STATE_STALL */
 
STATE_LD: begin
pc_next = PC + 1;
next_state = STATE_NORMAL;
end /* STATE_LD */
 
STATE_CALL: begin
sp_next = SP - 1;
sp_update = 1;
pc_next = pc_call;
next_state = STATE_STALL;
end /* STATE_CALL */
 
STATE_RET: begin
pc_call_next = { 8'h00, dmem_di };
sp_next = SP + 1;
sp_update = 1;
next_state = STATE_RET2;
end /* STATE_RET2 */
 
STATE_RET2: begin
pc_next = { dmem_di, pc_call[7:0] };
next_state = STATE_STALL;
end /* STATE_RET2 */
 
STATE_SKIP: begin
if (two_word_instr) next_state = STATE_STALL;
else next_state = STATE_NORMAL;
pc_next = PC + 1;
end /* STATE_SKIP */
 
STATE_LPM: begin
pc_next = pc_call;
next_state = STATE_LPM2;
end
 
STATE_LPM2: begin
pc_next = PC + 1;
next_state = STATE_NORMAL;
end
 
STATE_ADIW: begin
if (PREVI[8]) begin
/* SBIW */
{nC, R_high} = GPR[24+2*Rp16+1] - C;
nV = GPR[24+2*Rp16+1][7] & ~R_high[7];
end else begin
/* ADIW */
{nC, R_high} = GPR[24+2*Rp16+1] + C;
nV = ~GPR[24+2*Rp16+1][7] & R_high[7];
end
nN = R_high[7];
nS = nN ^ nV;
nZ = (R_high==0) & Z;
pc_next = PC + 1;
next_state = STATE_NORMAL;
end
 
STATE_IO_BIT: begin
pc_next = PC + 1;
next_state = STATE_NORMAL;
end
 
 
`ifdef AVR_INITIAL
STATE_INITIAL: begin
if (init_count[init_depth-1] == 1'b1)
next_state = STATE_STALL;
else
next_state = STATE_INITIAL;
end
`endif
 
`ifdef AVR_HAVE_MUL
STATE_MUL: begin
 
{ R_high, R } = product;
if ( mul_type[0] & mul_rd[7] )
R_high = R_high - mul_rr;
if ( mul_type[1] & mul_rr[7] )
R_high = R_high - mul_rd;
 
nZ = ( {R_high, R} == 16'h0000 );
nC = R_high[7];
 
if ( mul_type[2] ) begin
{ R_high, R } = { R_high[6:0], R, 1'b0 };
end
 
pc_next = PC + 1;
next_state = STATE_NORMAL;
end
`endif
 
endcase
 
end /* always @(*) */
 
// Note: if `interrupt` is 1, then after this point:
// - state is STATE_NORMAL,
// - writeback is 0,
// - next_state is STATE_CALL.
 
`ifdef AVR_HAVE_MUL
always @(posedge clk) if (next_state==STATE_MUL) begin
product <= GPR_Rd_mul * GPR_Rr_mul;
mul_rd <= GPR_Rd_mul;
mul_rr <= GPR_Rr_mul;
mul_type <= { fmulxx, xmulsx, xmulsu };
end
`endif
 
always @(posedge clk) begin
 
`ifdef AVR_HAVE_MUL
if (state==STATE_MUL) begin
/* writeback: after two-cycle MUL: */
GPR[0] <= R;
GPR[1] <= R_high;
end else
`endif
 
`ifdef AVR_HAVE_MOVW
/* writeback: after single cycle MOVW: */
if (state==STATE_NORMAL && INSTR[15:8]==8'b0000_0001 && ~is_interrupt) begin
GPR[2*RD16+0] <= R; // GPR[2*RR16+0];
GPR[2*RD16+1] <= R_high; // GPR[2*RR16+1];
end else
`endif
 
/* writeback: after the first and second cycle of ADIW and SUBW: */
if (next_state==STATE_ADIW)
GPR[24+2*Rd16+0] <= R;
else if (state==STATE_ADIW)
GPR[24+2*Rp16+1] <= R_high;
/* writeback after LD: */
else if ( state==STATE_LD )
GPR[Rd_ld_save] <= dmem_di;
else if ( state==STATE_LPM2 ) begin
if (~lpm_z_low) GPR[Rd_ld_save] <= INSTR[7:0];
else GPR[Rd_ld_save] <= INSTR[15:8];
end else begin
 
/* writeback: all of the another cases (ALU + X/Y/Z inc/dec): */
case (writeback)
WRITEBACK_GPR: begin
GPR[Rd] <= R;
end
WRITEBACK_ZINC: begin
GPR[30] <= RZ_inc[7:0];
GPR[31] <= RZ_inc[15:8];
end
WRITEBACK_ZY: begin
if (~INSTR[3]) begin
GPR[30] <= RZ_inc_dec[7:0];
GPR[31] <= RZ_inc_dec[15:8];
end else begin
GPR[28] <= RY_inc_dec[7:0];
GPR[29] <= RY_inc_dec[15:8];
end
end
WRITEBACK_X: begin
GPR[26] <= RX_inc_dec[7:0];
GPR[27] <= RX_inc_dec[15:8];
end
endcase
 
end
 
{ I, T, H, S, V, N, Z, C } <= nSREG;
 
if (~INSTR[9]) Rio <= Rin & ~(8'h01 << b);
else Rio <= Rin | (8'h01 << b);
 
pc_call <= pc_call_next;
 
if (next_state == STATE_LD)
Rd_ld_save <= (state == STATE_NORMAL ? Rd : Rd_prev);
else if (next_state == STATE_LPM) begin
Rd_ld_save <= (INSTR[10] ? 5'b00000: Rd);
lpm_z_low <= RZ[0];
end
 
`ifdef AVR_INITIAL
if ( ~init_count[init_depth-1] )
init_count <= init_count + 1;
`endif
 
state <= next_state;
PC <= pc_next;
 
// if ( sp_update )
SP <= sp_next;
 
end
 
/*****************************************************************************/
 
/* Debug section starts here */
 
wire [pmem_width:0] PC_double = {PC,1'b0};
wire [7:0] R0 = GPR[0];
wire [7:0] R1 = GPR[1];
wire [7:0] R2 = GPR[2];
wire [7:0] R3 = GPR[3];
wire [7:0] R4 = GPR[4];
wire [7:0] R5 = GPR[5];
wire [7:0] R6 = GPR[6];
wire [7:0] R7 = GPR[7];
wire [7:0] R8 = GPR[8];
wire [7:0] R9 = GPR[9];
wire [7:0] R10 = GPR[10];
wire [7:0] R11 = GPR[11];
wire [7:0] R12 = GPR[12];
wire [7:0] R13 = GPR[13];
wire [7:0] R14 = GPR[14];
wire [7:0] R15 = GPR[15];
wire [7:0] R16 = GPR[16];
wire [7:0] R17 = GPR[17];
wire [7:0] R18 = GPR[18];
wire [7:0] R19 = GPR[19];
wire [7:0] R20 = GPR[20];
wire [7:0] R21 = GPR[21];
wire [7:0] R22 = GPR[22];
wire [7:0] R23 = GPR[23];
wire [7:0] R24 = GPR[24];
wire [7:0] R25 = GPR[25];
wire [7:0] R26 = GPR[26];
wire [7:0] R27 = GPR[27];
wire [7:0] R28 = GPR[28];
wire [7:0] R29 = GPR[29];
wire [7:0] R30 = GPR[30];
wire [7:0] R31 = GPR[31];
 
`ifdef SIMULATOR
initial begin
$dumpvars(1,PC,PC_double,INSTR,SP,SREG,state,pc_call,R);
$dumpvars(1,R0,R1,R16,R17,R18,R19,R20,R21,R22,R23,R24,R25,RX,RY,RZ);
$dumpvars(1,io_we,io_re,io_a,io_do,io_di,Rio);
$dumpvars(1,dmem_we,dmem_re,dmem_a,dmem_do,dmem_di);
end
`endif
 
/* end of debug section */
/*****************************************************************************/
 
endmodule
 
/*****************************************************************************/
/trunk/doc/diagram.txt
0,0 → 1,9
This section is still to be done...
 
/-----\ /-----\ /-----\ /-----\
CLK: / \ / \ / \ / \ /
\-----/ \-----/ \-----/ \-----/
 
/-------------\ /-------------\ /-------------\ /-------------\
< X X X X
\-------------/ \-------------/ \-------------/ \-------------/
/trunk/peripherals/avr_io_out.v
0,0 → 1,42
/*****************************************************************************/
/* avr_io_out.v */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* (c) 2019-2020; Andras Pal <apal@szofi.net> */
/*****************************************************************************/
 
module avr_io_out
( input clk,
input rst,
 
input io_re,
input io_we,
output [7:0] io_do,
input [7:0] io_di,
 
output [7:0] port
);
 
reg [7:0] PORT;
 
assign port[7:0] = PORT[7:0];
 
assign io_do = io_re ? PORT : 8'b00000000;
 
always @(posedge clk) begin
 
if (io_we) begin
PORT <= io_di;
end
 
end
 
 
/*****************************************************************************/
/* Debug section starts here */
 
/* end of debug section */
/*****************************************************************************/
 
endmodule
 
/*****************************************************************************/
/trunk/peripherals/avr_io_timer.v
0,0 → 1,95
/*****************************************************************************/
/* avr_io_timer.v */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* (c) 2019-2020; Andras Pal <apal@szofi.net> */
/*****************************************************************************/
 
module avr_io_timer
( input clk,
input rst,
 
input io_re,
input io_we,
input [1:0] io_a,
output [7:0] io_do,
input [7:0] io_di,
output irq
);
 
reg [15:0] TCNT;
reg [7:0] TTMP;
reg [7:0] TCR;
 
reg [11:0] prescaler;
reg [3:0] pre_prev;
reg overflow;
 
wire [7:0] TSR = { overflow, 7'b0000000 };
 
assign irq = TSR[7] & TCR[7];
 
/* I/O read: */
reg [7:0] io_do_data;
always @(*) begin
casex (io_a)
2'b00: io_do_data = TCNT[7:0];
2'b01: io_do_data = TTMP[7:0];
2'b10: io_do_data = TCR;
2'b11: io_do_data = TSR;
endcase
end
assign io_do = io_re ? io_do_data : 8'b00000000;
 
 
always @(posedge clk) begin
 
if (io_we & ~io_re) begin
if ( io_a==2'b01 ) TTMP <= io_di;
if ( io_a==2'b10 ) TCR <= io_di;
end else if ( io_re ) begin
if ( io_a==2'b00 )
TTMP <= TCNT[15:8];
end
 
end
 
wire tcnt_write = io_we & (io_a==2'b00);
wire tcr_write = io_we & (io_a==2'b10);
 
/* Note: the interrupt is cleared when the overflow flag is reset: therefore, any write
into the TNCT _or_ the TCR register would clear the interrupt: */
 
wire o = overflow & (~tcr_write);
 
reg increment;
 
always @(*) begin
casex (TCR[1:0])
2'b00: increment = 1;
2'b01: increment = (~prescaler[ 3])&pre_prev[0];
2'b10: increment = (~prescaler[ 7])&pre_prev[1];
2'b11: increment = (~prescaler[11])&pre_prev[2];
endcase
end
 
always @(posedge clk) begin
if ( ! tcnt_write ) begin
prescaler <= prescaler + 1;
pre_prev <= { prescaler[11], prescaler[7], prescaler[3] };
{ overflow, TCNT } <= { o, 16'd0 } | ( { o, TCNT } + increment );
end else begin
TCNT <= { TTMP, io_di };
prescaler <= 0;
overflow <= 0;
end
end
 
/*****************************************************************************/
/* Debug section starts here */
 
/* end of debug section */
/*****************************************************************************/
 
endmodule
 
/*****************************************************************************/
/trunk/peripherals/avr_io_uart.v
0,0 → 1,244
/*****************************************************************************/
/* avr_io_uart.v */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* (c) 2019-2020; Andras Pal <apal@szofi.net> */
/*****************************************************************************/
 
module uart_tx (input clk, input [7:0] prescaler, input [7:0] tx_in, input strobe, output reg txd, output busy, output prefetch);
 
parameter TX_STATE_IDLE = 0;
parameter TX_STATE_TRANSMIT = 1;
 
reg state = TX_STATE_IDLE;
 
//reg txd = 1;
 
reg [7:0] count = 0;
reg [7:0] scaler_counter = 0;
 
reg [7:0] dataout = 0;
 
parameter count_step = 2;
assign busy = state;
 
wire scaler_limit = (scaler_counter==0);
wire bit_limit = (count[3:0] == 4'b0000);
wire last_bit = (count[7:4]==4'd10);
 
assign prefetch = ( state==TX_STATE_TRANSMIT ) & scaler_limit & bit_limit & last_bit;
 
always @(posedge clk) begin
if ( state==TX_STATE_IDLE && strobe ) begin
state <= TX_STATE_TRANSMIT;
txd <= 0;
count <= count_step;
dataout <= tx_in;
scaler_counter <= prescaler;
end else if ( state==TX_STATE_TRANSMIT && scaler_limit ) begin
if ( bit_limit ) begin
if ( last_bit ) begin
if ( strobe ) begin
txd <= 0;
count <= count_step;
dataout <= tx_in;
end else begin
txd <= 1;
state <= TX_STATE_IDLE;
end
end else begin
txd <= dataout[0];
dataout <= { 1'b1, dataout[7:1] };
count <= count + count_step;
end
end else begin
count <= count + count_step;
end
scaler_counter <= prescaler;
end else if ( state==TX_STATE_TRANSMIT ) begin
scaler_counter <= scaler_counter - 1;
end
 
end
 
endmodule
 
/*****************************************************************************/
 
module uart_rx (input clk, input [7:0] prescaler, input rxd, input reset, output [7:0] rx_out, output reg avail);
 
parameter STATE_IDLE = 0;
parameter STATE_STARTBIT = 2;
parameter STATE_RECEIVE = 3;
 
reg [1:0] state = STATE_IDLE;
 
reg [7:0] count = 0;
reg [7:0] scaler_counter = 0;
 
reg [7:0] datain = 0;
//reg avail = 0;
 
parameter count_step = 2;
 
wire rx_sub_bit = ( state==STATE_RECEIVE && scaler_counter==0 );
wire rx_bit = (rx_sub_bit && count[3:0] == 4'b0000);
wire rx_completed = (rx_bit && count[7:4]==4'd9 );
 
assign rx_out = datain;
 
always @(posedge clk) begin
if ( state==STATE_IDLE && rxd==0 ) begin
state <= STATE_STARTBIT;
count <= count_step;
scaler_counter <= prescaler;
end else if ( state==STATE_STARTBIT && scaler_counter==0 ) begin
if ( count[3:0] == 4'b1000 ) begin
state <= STATE_RECEIVE;
count <= count_step;
end else begin
count <= count + count_step;
end
scaler_counter <= prescaler;
end else if ( state==STATE_RECEIVE && scaler_counter==0 ) begin
if ( count[3:0] == 4'b0000 ) begin
if ( count[7:4]==4'd9 ) begin
state <= STATE_IDLE;
end else begin
datain <= { rxd, datain[7:1] };
count <= count + count_step;
end
end else begin
count <= count + count_step;
end
scaler_counter <= prescaler;
end else if ( state[1] ) begin
scaler_counter <= scaler_counter - 1;
end
 
avail <= rx_completed | (avail & ~reset);
 
end
 
endmodule
 
/*****************************************************************************/
 
module avr_io_uart
( input clk,
input rst,
 
input io_re,
input io_we,
input [1:0] io_a,
output [7:0] io_do,
input [7:0] io_di,
 
output txd,
input rxd,
 
output [2:0] irq
);
 
reg [7:0] UDR_TX = 0;
reg [7:0] UDR_RX = 0;
reg [7:0] UCSRB = 0;
reg [7:0] UBRR = 0;
 
parameter UCSRA_RXB8 = 3'd0;
parameter UCSRA_x1 = 3'd1;
parameter UCSRA_PE = 3'd2;
parameter UCSRA_DOR = 3'd3;
parameter UCSRA_FE = 3'd4;
parameter UCSRA_UDRE = 3'd5;
parameter UCSRA_TXC = 3'd6;
parameter UCSRA_RXC = 3'd7;
 
wire RXCIE, TXCIE, UDRIE, USBS, UPM1, UPM0, UCSZ, TXB8;
assign { RXCIE, TXCIE, UDRIE, USBS, UPM1, UPM0, UCSZ, TXB8 } = UCSRB;
 
reg rx0_non_empty = 0, rx0_overrun = 0, rx0_reset = 0;
wire tx0_txd,tx0_busy,tx0_prefetch;
reg tx0_non_empty = 0;
 
wire [7:0] UCSRA = { rx0_non_empty, ~tx0_busy, ~tx0_non_empty, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0 };
 
assign irq = UCSRB[7:5] & UCSRA[7:5];
 
/* I/O read: */
reg [7:0] io_do_data;
always @(*) begin
casex (io_a)
2'b00: io_do_data = UDR_RX[7:0];
2'b01: io_do_data = UCSRA;
2'b10: io_do_data = UCSRB;
2'b11: io_do_data = UBRR;
endcase
end
assign io_do = io_re ? io_do_data : 8'b00000000;
 
/* I/O write: configuration: */
always @(posedge clk) begin
if ( io_we ) begin
casex (io_a)
2'b10: UCSRB <= io_di;
2'b11: UBRR <= io_di;
endcase
end
end
 
/* TX */
 
 
uart_tx tx0 (clk, UBRR, UDR_TX, tx0_non_empty, tx0_txd, tx0_busy, tx0_prefetch);
 
/* transmitter state changes: */
always @(posedge clk) begin
if ( io_we && io_a == 2'b00 && ~tx0_non_empty ) begin
tx0_non_empty <= 1;
UDR_TX <= io_di;
end else if ( (tx0_non_empty & ~tx0_busy) | tx0_prefetch )
tx0_non_empty <= 0;
end
 
assign txd = tx0_txd | (~tx0_busy);
 
/* RX */
 
wire [7:0] rx0_data;
wire rx0_avail;
 
uart_rx rx0 (clk, UBRR, rxd, rx0_reset, rx0_data, rx0_avail);
 
/* receiver state changes: */
always @(posedge clk) begin
if ( io_re && io_a == 2'b00 ) begin
rx0_non_empty <= 0;
rx0_overrun <= 0;
end else if ( rx0_avail && ~rx0_reset ) begin
UDR_RX <= rx0_data;
rx0_non_empty <= 1;
rx0_overrun <= rx0_non_empty;
rx0_reset <= 1;
end else begin
rx0_reset <= 0;
end
end
 
/*****************************************************************************/
/* Debug section starts here */
 
`ifdef SIMULATOR
initial begin
$dumpvars(1,UDR_TX,UDR_RX,UCSRB,UBRR,tx0_non_empty,tx0_busy,tx0_prefetch);
$dumpvars(1,rxd,rx0_non_empty,rx0_avail,rx0_data,rx0_reset,rx0_overrun);
end
`endif
 
/* end of debug section */
/*****************************************************************************/
 
endmodule
 
/*****************************************************************************/
/trunk/peripherals/avr_systick.v
0,0 → 1,80
/*****************************************************************************/
/* avr_systick.v */
/*****************************************************************************/
/* Registers */
/* STCNTL r BASE + 0x00 { CNT[7:0] } */
/* STCNTH r BASE + 0x01 { OVERFLOW, CNT[14:8] } */
/* STLOADL r+w BASE + 0x02 { CLOAD[7:0] } */
/* STLOADH r+w BASE + 0x03 { IENABLE, CLOAD[14:8] } */
/*****************************************************************************/
 
module avr_systick
( input clk,
input rst,
 
input io_re,
input io_we,
input [1:0] io_a,
output [7:0] io_do,
input [7:0] io_di,
output irq
);
 
reg IENABLE;
reg CLOAD[14:0];
reg OVERFLOW;
reg [14:0] CNT;
reg [6:0] CTMP;
 
assign irq = IENABLE & OVERFLOW;
 
/* I/O read: */
reg [7:0] io_do_data;
always @(*) begin
casex (io_a)
2'b00: io_do_data = CNT[7:0];
2'b01: io_do_data = { OVERFLOW, CTMP };
2'b10: io_do_data = CLOAD[7:0];
2'b11: io_do_data = { IENABLE, CLOAD[14:8] } ;
endcase
end
 
assign io_do = io_re ? io_do_data : 8'b00000000;
 
wire reset_overflow_bit = (io_we & (io_a[1]==0));
 
always @(posedge clk) begin
 
if (io_we & ~io_re) begin
if ( io_a==2'b10 ) begin
CLOAD[7:0] <= io_di;
end else if ( io_a==2'b11 ) begin
{ IENABLE, CLOAD[14:8] } <= io_di;
end
end else if ( io_re ) begin
if ( io_a==2'b00 )
CTMP <= CNT[15:8];
end
 
end
 
always @(posedge clk) begin
if ( reset_overflow_bit ) begin
OVERFLOW <= 0;
end else if ( CNT[14:0]==0 ) begin
CNT <= CLOAD;
OVERFLOW <= 1;
end else begin
CNT <= CNT - 1;
end
end
 
/*****************************************************************************/
/* Debug section starts here */
 
/* end of debug section */
/*****************************************************************************/
 
endmodule
 
/*****************************************************************************/
/trunk/synth/Makefile
0,0 → 1,27
SHELL=/bin/bash
 
SYNTH=yosys
PNR=nextpnr-ice40
PACK=icepack
 
DEVICE=hx8k
#PACKAGE=bg121
PACKAGE=ct256
 
.PHONY: all clean
 
TOP=top
 
all: $(TOP).bin
 
$(TOP).json: $(TOP).v
$(SYNTH) -q -p 'synth_ice40 -top $(TOP) -json $(TOP).json' $(TOP).v
 
$(TOP).asc: $(TOP).json $(TOP).pcf
$(PNR) --$(DEVICE) --package $(PACKAGE) --json $(TOP).json --pcf $(TOP).pcf --seed 1 --randomize-seed --asc $(TOP).asc
 
$(TOP).bin: $(TOP).asc
$(PACK) $(TOP).asc $(TOP).bin
 
clean:
rm -f $(TOP).bin $(TOP).asc $(TOP).json
/trunk/synth/avr_core.v
0,0 → 1,27
link ../core/avr_core.v
trunk/synth/avr_core.v Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/avr_io_out.v =================================================================== --- trunk/synth/avr_io_out.v (nonexistent) +++ trunk/synth/avr_io_out.v (revision 2) @@ -0,0 +1 @@ +link ../peripherals/avr_io_out.v \ No newline at end of file
trunk/synth/avr_io_out.v Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/avr_io_timer.v =================================================================== --- trunk/synth/avr_io_timer.v (nonexistent) +++ trunk/synth/avr_io_timer.v (revision 2) @@ -0,0 +1 @@ +link ../peripherals/avr_io_timer.v \ No newline at end of file
trunk/synth/avr_io_timer.v Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/avr_io_uart.v =================================================================== --- trunk/synth/avr_io_uart.v (nonexistent) +++ trunk/synth/avr_io_uart.v (revision 2) @@ -0,0 +1 @@ +link ../peripherals/avr_io_uart.v \ No newline at end of file
trunk/synth/avr_io_uart.v Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/flash.v =================================================================== --- trunk/synth/flash.v (nonexistent) +++ trunk/synth/flash.v (revision 2) @@ -0,0 +1,26 @@ +module flash + #( parameter flash_file = "main.mem", + parameter flash_width = 10 + ) + ( input clk, + input mem_ce, + input [flash_width-1:0] mem_a, + output [15:0] mem_d + ); + +reg [15:0] flash_array [0:2**flash_width-1]; + +reg [15:0] data_read; + +assign mem_d = data_read; + +always @(posedge clk) begin + if (mem_ce) data_read <= flash_array[mem_a]; +end + +initial begin +// $readmemh(flash_file, flash_array); + `include "flash_array.v" +end + +endmodule Index: trunk/synth/flash_array.v =================================================================== --- trunk/synth/flash_array.v (nonexistent) +++ trunk/synth/flash_array.v (revision 2) @@ -0,0 +1 @@ +link ../build/flash_array.v \ No newline at end of file
trunk/synth/flash_array.v Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/main.mem =================================================================== --- trunk/synth/main.mem (nonexistent) +++ trunk/synth/main.mem (revision 2) @@ -0,0 +1 @@ +link ../build/main.mem \ No newline at end of file
trunk/synth/main.mem Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/main.v =================================================================== --- trunk/synth/main.v (nonexistent) +++ trunk/synth/main.v (revision 2) @@ -0,0 +1 @@ +link ../build/main.v \ No newline at end of file
trunk/synth/main.v Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/ram.v =================================================================== --- trunk/synth/ram.v (nonexistent) +++ trunk/synth/ram.v (revision 2) @@ -0,0 +1,25 @@ +module ram + #( parameter ram_width = 9 + ) + ( input clk, + input re, + input we, + input [ram_width-1:0] addr, + output [7:0] data_read, + input [7:0] data_write + ); + +reg [7:0] ram_array [0:2**ram_width-1]; +reg [7:0] data_out; + +assign data_read = data_out; + +always @(posedge clk) begin + if (we) ram_array[addr] <= data_write; +end + +always @(posedge clk) begin + if (re) data_out <= ram_array[addr]; +end + +endmodule Index: trunk/synth/top-bg121.pcf =================================================================== --- trunk/synth/top-bg121.pcf (nonexistent) +++ trunk/synth/top-bg121.pcf (revision 2) @@ -0,0 +1,25 @@ +# GRBAlpha ballon payload board + +set_io led[1] A4 +set_io led[0] B4 + +set_io hwclk L5 + +# This is the input for the FPGA, signal comes from the FT2232: +set_io ftdi_rx K7 +# This is the output for the FPGA, signal goes to the FT2232: +set_io ftdi_tx L7 + +set_io sseg4[12] B2 # DD +set_io sseg4[11] D2 # D1 +set_io sseg4[10] C2 # D2 +set_io sseg4[9] A2 # D3 +set_io sseg4[8] B3 # D4 +set_io sseg4[7] G2 # a +set_io sseg4[6] E2 # b +set_io sseg4[5] H1 # c +set_io sseg4[4] E1 # d +set_io sseg4[3] F1 # e +set_io sseg4[2] F2 # f +set_io sseg4[1] D1 # g +set_io sseg4[0] G1 # dp Index: trunk/synth/top-ct256.pcf =================================================================== --- trunk/synth/top-ct256.pcf (nonexistent) +++ trunk/synth/top-ct256.pcf (revision 2) @@ -0,0 +1,35 @@ +# iCE40HX8K-CT256 ICE40HX8K-B-EVN + +set_io led[7] B5 +set_io led[6] B4 +set_io led[5] A2 +set_io led[4] A1 +set_io led[3] C5 +set_io led[2] C4 +set_io led[1] B3 +set_io led[0] C3 + +set_io hwclk J3 + +# This is the input for the FPGA top module: +set_io ftdi_rx B10 # input +# This is the output for the FPGA top module: +set_io ftdi_tx B12 # output + +set_io pin_scl0 D16 +set_io pin_sda0 C16 + +# Another 5 ports connected to the FTDI transceiver: +#set_io ftdi_nrts B13 # input +#set_io ftdi_ncts A15 # output +#set_io ftdi_ndtr A16 # input +#set_io ftdi_ndsr B14 # output +#set_io ftdi_ndcd B15 # output +#set_io ftdi_rx B9 # orange +#set_io ftdi_tx A7 # yellow +#set_io nss B8 +#set_io sck A9 +#set_io miso A10 +#set_io mosi A11 + + Index: trunk/synth/top-digilent_nexys_a7-cx7a100t.xdc =================================================================== --- trunk/synth/top-digilent_nexys_a7-cx7a100t.xdc (nonexistent) +++ trunk/synth/top-digilent_nexys_a7-cx7a100t.xdc (revision 2) @@ -0,0 +1,11 @@ +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN E3 } [get_ports hwclk] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN H17 } [get_ports {led[0]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN K15 } [get_ports {led[1]}] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN C4 } [get_ports ftdi_rx] +set_property -dict { IOSTANDARD LVCMOS33 PACKAGE_PIN D4 } [get_ports ftdi_tx] + +create_clock -period 10 [get_ports hwclk] + +set_property CONFIG_VOLTAGE 3.3 [current_design] +set_property CFGBVS VCCO [current_design] + Index: trunk/synth/top.pcf =================================================================== --- trunk/synth/top.pcf (nonexistent) +++ trunk/synth/top.pcf (revision 2) @@ -0,0 +1 @@ +link top-ct256.pcf \ No newline at end of file
trunk/synth/top.pcf Property changes : Added: svn:special ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/synth/top.v =================================================================== --- trunk/synth/top.v (nonexistent) +++ trunk/synth/top.v (revision 2) @@ -0,0 +1,237 @@ +`include "avr_core.v" +`include "avr_io_out.v" +`include "avr_io_uart.v" +`include "avr_io_timer.v" +`include "main.v" +//`include "flash.v" +`include "ram.v" + +//`include "avr_io_spi.v" + +/*****************************************************************************/ + +module priority_encoder ( input [3:0] irq_lines , output iflag, output reg [1:0] ivect ); + +//reg [1:0] ivect; + +always @(*) begin + if (irq_lines[0]) ivect = 0; + else if (irq_lines[1]) ivect = 1; + else if (irq_lines[2]) ivect = 2; + else if (irq_lines[3]) ivect = 3; + else ivect = 0; +end + +assign iflag = |irq_lines; + +endmodule + +/*****************************************************************************/ + +module top + ( input hwclk, + output [7:0] led, + input ftdi_rx, + output ftdi_tx, + inout pin_scl0, + inout pin_sda0 + + ); + +//assign sseg4 = 13'b1_1111_1111_1111; + +wire clk; + +parameter pmem_width = 10; +parameter dmem_width = 9; + +wire pmem_ce; +wire [pmem_width-1:0] pmem_a; +wire [15:0] pmem_d; + +wire dmem_re; +wire dmem_we; +wire [dmem_width-1:0] dmem_a; +wire [7:0] dmem_di; +wire [7:0] dmem_do; + +wire io_re; +wire io_we; +wire [5:0] io_a; +wire [7:0] io_do; + + +SB_PLL40_CORE + #( .FEEDBACK_PATH("SIMPLE"), + .PLLOUT_SELECT("GENCLK"), + .ENABLE_ICEGATE("0"), + .DIVR(4'b0000), + .DIVF(7'b0111111), + .DIVQ(3'b100), + .FILTER_RANGE(3'b001) + ) +pll + ( .RESETB(1'b1), + .BYPASS(1'b1), + .EXTFEEDBACK(1'b0), + .LATCHINPUTVALUE(1'b0), + .DYNAMICDELAY(8'b00000000), + .REFERENCECLK(hwclk), + .SDI(1'b0), + .SCLK(1'b0), + .PLLOUTGLOBAL(clk) + ); + +//reg [1:0] clkcnt; +//always @(posedge hwclk) clkcnt <= clkcnt + 1; +//assign clk = clkcnt[1]; +//BUFG clkcrt ( .I(clkcnt[1]), .O(clk) ); + +/*****************************************************************************/ + +ram core0_ram ( clk, dmem_re, dmem_we, dmem_a, dmem_di, dmem_do ); +defparam core0_ram.ram_width = dmem_width; + +flash core0_flash ( clk, pmem_ce,pmem_a, pmem_d ); +//defparam core0_flash.flash_width = pmem_width; + +/*****************************************************************************/ + +wor [7:0] io_di; + +`define TIMER0 + +`ifdef TIMER0 +wire timer0_io_select = (io_a[5:2] == 4'b0010); +wire timer0_io_re = timer0_io_select & io_re; +wire timer0_io_we = timer0_io_select & io_we; +wire timer0_irq; + +avr_io_timer timer0 + ( clk, 1'b0, + timer0_io_re, timer0_io_we, io_a[1:0], io_di, io_do, + timer0_irq + ); +`else +wire timer0_irq = 0; +`endif + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +`define PORT0 + +`ifdef PORT0 +wire port0_io_select = (io_a[5:0] == 6'b000100); +wire port0_io_re = (port0_io_select ? io_re : 1'b0); +wire port0_io_we = (port0_io_select ? io_we : 1'b0); +wire [7:0] port0_out; + +avr_io_out port0 + ( clk, 1'b0, + port0_io_re, port0_io_we, io_di, io_do, + port0_out + ); + +assign led = port0_out; +`else +assign led = 8'b00000000; +`endif + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +`define UART0 + +`ifdef UART0 +wire uart0_io_select = (io_a[5:2] == 4'b0000); +wire uart0_io_re = (uart0_io_select ? io_re : 1'b0); +wire uart0_io_we = (uart0_io_select ? io_we : 1'b0); +wire uart0_txd; +wire uart0_rxd; +wire [2:0] uart0_irq; + +assign ftdi_tx = uart0_txd; +assign uart0_rxd = ftdi_rx; + +avr_io_uart uart0 + ( clk, 1'b0, + uart0_io_re, uart0_io_we, io_a[1:0], io_di, io_do, + uart0_txd, uart0_rxd, + uart0_irq + ); +`else +assign ftdi_tx = ftdi_rx; +wire [2:0] uart0_irq; +assign uart0_irq = 3'b000; +`endif + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// `define SPI0 + +`ifdef SPI0 +wire spi0_io_select = (io_a[5:2] == 4'b0100); +wire spi0_io_re = (spi0_io_select ? io_re : 1'b0); +wire spi0_io_we = (spi0_io_select ? io_we : 1'b0); +wire spi0_enable; +wire spi0_master; +wire spi0_master_out; +wire spi0_master_in; +wire spi0_master_clk; +wire spi0_master_select; +wire spi0_slave_out; + +`define ASYNC_SPI_SAMPLING + +`ifdef ASYNC_SPI_SAMPLING +assign mosi = spi0_master_out; +assign spi0_master_in = miso; +assign sck = spi0_master_clk; +assign nss = ~spi0_master_select; +`else +reg mosi, spi0_master_in, sck, nss; +always @(posedge clk) begin + mosi <= spi0_master_out; + spi0_master_in <= miso; + sck <= spi0_master_clk; + nss <= ~spi0_master_select; +end +`endif + +avr_io_spi spi0 + ( clk, 1'b0, + spi0_io_re, spi0_io_we, io_a[1:0], io_di, io_do, + spi0_enable, spi0_master, + spi0_master_clk, spi0_master_out, spi0_master_in, spi0_master_select, + 1'b0, 1'b0, spi0_slave_out, 1'b0 + ); +`else + +//assign sck = 1'b0; +//assign mosi = 1'b0; +//assign nss = 1'b1; + +`endif + + +/*****************************************************************************/ + +wire iflag; +wire [1:0] ivect; + +priority_encoder irq0 ( { uart0_irq[2], 1'b0, timer0_irq, 1'b0 }, iflag, ivect ); + +avr_core core0 + ( clk, 1'b0, + pmem_ce, pmem_a, pmem_d, + dmem_re, dmem_we, dmem_a, dmem_di, dmem_do, + io_re, io_we, io_a, io_di, io_do, + iflag, ivect + ); + +defparam core0.pmem_width = pmem_width; +defparam core0.dmem_width = dmem_width; +defparam core0.interrupt = 1; +defparam core0.intr_width = 2; + +endmodule + Index: trunk/util/progmem-generic.sh =================================================================== --- trunk/util/progmem-generic.sh (nonexistent) +++ trunk/util/progmem-generic.sh (revision 2) @@ -0,0 +1,67 @@ +#!/bin/bash + +infile="" + +depth=8 + +name=rom_16bit + +while [ -n "$1" ]; do + case "$1" in + -h|--help) + echo -e "Usage:\t$0 [-h|--help] [-w|--width ] <16-bit-image.bin>" + exit 0 + ;; + -w|--width|-d|--depth) + depth="$2" + shift + ;; + -n|--name) + name="$2" + shift + ;; + -*) + echo -e "$0: error: invalid command line argument near '$1'." >> /dev/stderr + exit 1 + ;; + *) + infile="$1" + ;; + esac; shift +done + +if ! [ -n "$infile" ] || ! [ -f "$infile" ]; then + echo "$0: error: input file is missing or not found." >> /dev/stderr + exit 1 +fi + +nword=$((1<
trunk/util/progmem-generic.sh Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/util/progmem-ice40.sh =================================================================== --- trunk/util/progmem-ice40.sh (nonexistent) +++ trunk/util/progmem-ice40.sh (revision 2) @@ -0,0 +1,115 @@ +#!/bin/bash + +infile="" + +depth=8 + +name=rom_16bit + +while [ -n "$1" ]; do + case "$1" in + -h|--help) + echo -e "Usage:\t$0 [-h|--help] [-w|--width ] <16-bit-image.bin>" + exit 0 + ;; + -w|--width|-d|--depth) + depth="$2" + shift + ;; + -n|--name) + name="$2" + shift + ;; + -*) + echo -e "$0: error: invalid command line argument near '$1'." >> /dev/stderr + exit 1 + ;; + *) + infile="$1" + ;; + esac; shift +done + +if ! [ -n "$infile" ] || ! [ -f "$infile" ]; then + echo "$0: error: input file is missing or not found." >> /dev/stderr + exit 1 +fi + +nword=$((1<
trunk/util/progmem-ice40.sh Property changes : Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: trunk/Makefile =================================================================== --- trunk/Makefile (nonexistent) +++ trunk/Makefile (revision 2) @@ -0,0 +1,12 @@ +SHELL=/bin/sh + +.PHONY: all clean + +all: + $(MAKE) -C build + $(MAKE) -C synth + +clean: + $(MAKE) -C build clean + $(MAKE) -C synth clean + Index: trunk/README =================================================================== --- trunk/README (nonexistent) +++ trunk/README (revision 2) @@ -0,0 +1,121 @@ +Soft AVR Core + Interfaces +========================== + +Introduction +------------ + +This package is a full-stack implementation of the AVR 2-stage pipeline, +featuring synthesis for AVR2 (classic core), AVR2.5 (classic plus), AVR3 +(with extended program memory), AVR4 (enhanced core) and AVR5 (enhanced core +with extended program memory). Interrupts are supported with customized number +of IRQ vector width. + +The project comes with some example peripherals, such as UART, SPI, a +basic timer, output port and SysTick timer. + +Synthetized and tested using various tools, including free & open source +packages: + - iCE40HX8K-BG121 and iCE40HX8K-CT256 (on ICE40HX8K-B-EVN and custom +design boards): Project IceStorm: yosys-0.9, nextpnr-ice40 and icestorm +utilities; + - iCE40HX8K-BG121 and iCE40HX8K-CT256 (on ICE40HX8K-B-EVN and custom +design boards): Lattice iCEcube2; and + - XA7A100T-1CSG324 (on a Digilent Nexys A7 board): Xilinx Vivado 2019.1. + +Software run by the core can seamlessly be built with the AVR-GCC +toolchain. This bundle includes utilities aiding the conversion from ELF +output to BRAM initializations (designed for iCE40 EBRs) or generic +synchronous ROM interface to set up the initial program memory. A +configurable startup code (crt0.s) is included in the package with +options to be matched to the synthetized core architecture. + +Availability +------------ + +This package is available from https://szofi.net/pub/verilog/softavrcore/. +Select the softavrcore-latest.tar.gz file for the latest version. Comments +are welcomed! Contact: Andras Pal . + +Getting started +--------------- + + - On a Linux system, install the following toolchains and utilities: + * gcc-avr + * avr-libc + * binutils-avr + * icestorm + * yosys + * nextpnr-ice40 + then enter `make` in the main directory. This will compile the example + C code (found in ./build) and then run the synthesis and place-and-route + targeted for the ICE40HX8K-B-EVN board. This step is automatically following + by the generation of the FPGA configuration bitstream for iCE40HX8K-CT256 + in the file top.bin. + + - On another operating systems for non-Lattice FPGA targets: + * use the corresponding AVR port to compile the source and create + the main.bin file. A working bash/awk is needed to automatically + create the *.v files containing the flash interface for this + virtual MCU. These are available on MacOS by default. On Windows, you + may need to install additional components (e.g. Cygwin). + * Collect the source *.v files, including the core (avr_core.v), + peripherals (avr_io_*.v), flash interface (main.v), data memory + (ram.v) and the top module (top.v) into a single directory _if_ your + operating system does not support symlinks. + * Import the top.v to your synthesis toolchain (icecube2, vivado, ...). + You can use the shipped *.pcf files for Lattice tools (such as + icecube2) without any further modifications. For Xilinx, you may + use the file top-digilent_nexys_a7-cx7a100t.xdc as a starting point, + or use it without any modifications for the Digilent Nexys A7 board. + +By default the example code (./build/main.c) sends the following series of +messages via the built-in secondary UART interface of the ICE40HX8K-B-EVN +board at 115200 baud: + [x] 0 => 0 + [x] 1 => 1 + [x] 2 => 4 + [x] 3 => 9 + [x] 4 => 16 + [x] 5 => 25 + [x] 6 => 36 + ... +Here the cadence is one message per minute. The cores and the C code expect +a 12MHz clock input for baud rate configuration and during the computation +of the timer delay. + +You may change the contents of the main() function to switch to another +examples. Note also that the example is fitted for 1024 words of program code +(i.e. 2048 bytes of program flash memory). Change top.v and ./build/Makefile +accordingly for larger (or smaller) program memory configurations. + +Known issues +------------ + + - LD/ST operations work only on data memory interface, not on the I/O +port and the register file. GCC is not known to generate such code unless +register mappings are explicitly indexed with the X, Y or Z pointer registers. +Since registers are not available directly for C code and I/O ports are +defined to be constants for all of the relevant peripherals, it is not +expected at all and access to those areas are seamlessly translated by GCC to +the faster MOV, IN and OUT instructions instead of LD/ST. + - SPM instruction is not supported, however, equivalent +self-programming interfaces can be synthetized by custom peripherals. + - Watchdog is not supported, however, equivalent functionality can be +synthetized by custom peripherals. + - Automatic interrupt acknowledgement is not supported at the moment. + - Fuse bits and in-system programming are not supported. These are, in +practice, nearly meaningless on such an FPGA-based CPU/MCU implementation. + - This soft AVR CPU is cycle compatible with the exception of the store +operations (LD, LDS, LDD, PUSH). These store operations runs faster by 1 cycle +compared to the AVR hardware. Use a preceeding or following NOP to be +cycle compatible with off-the-shelf AVR hardware. + +Coming soon +----------- + + - I2C peripheral + - CAN bus interface + - An implementation of the AVR architecture using a 4-stage pipeline + - FreeRTOS port + - some more detaild documentation +

powered by: WebSVN 2.1.0

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