/****************************************** Simple 16bit Non-Pipeline Processor (SN/X) V1.1 Synthesizable SFL source code. (C)Copyright by Naohiko Shimizu, 2001. All rights are reserved. Contact information: Dr. Naohiko Shimizu School of Engineering, Tokai University 1117 Kitakaname, Hiratsuka-city, Kanagawa, 259-1292, Japan email: nshimizu@et.u-tokai.ac.jp URL: http://shimizu-lab.et.u-tokai.ac.jp/ Features of the processor: Data 16bit, Instruction 16bit, Harvard architecture, 16bit data/inst address spaces, load/store architecture, It has two types of instruction, i.e. R-type and I-type. R-type instructions |OP|r2|r3|r1| - | ... r1 <- r2 op r3 The instructions belong to the R-type are: ADD addition AND logical and SLT set less than (like MIPS architecture) NOT logical not SR logical shift right by one I-type instructions |OP|r1|r2| I | ... r1 <- r2(I) where I is 8bit but used as a sign extended 16bit data. The instructions belong to the I-type are: LD load from memory ST store to memory LDA load address(or add immediate) BZ branch on r1 is zero BAL branch and link IN input ----- not implemented OUT output ----- not implemented RI Return from interrupt ----- not implemented C to SN/X translation sample: ABI: procedure return value : $1 procedure argument (1st): $1 procedure return address : $2 frame pointer : $3 global pointer : in memory at 'gp' size of integer: 16bit Consider the following C code. int foo(int k) { if(k == 0) return(0); return(k+foo(k-1)); } You can translate this code into the SN/X assembler code like following: .entry foo foo: lda $3,-2($3) ; reserve two integers st $2,0($3) ; save return address st $1,1($3) ; save local argument 'k' bz $1,foo_1 ; if 'k' is equal to 0, return lda $1,-1($1) ; make 'k-1' bal $2,foo ; call foo ld $2,1($3) ; load local argument 'k' add $1,$1,$2 ; calculate 'k+return value of foo' foo_1: ld $2,0($3) ; load return address lda $3,2($3) ; calculate original frame pointer bal $2,0($2) ; return from procedure .end Update informations: 28-Jun-2002: State added for PARTHENON lecture 16-Jul-2001: SLT change to get valid result on overflow case 21-Jun-2001: Modify snx core interface to "top" for synthesis lecture 02-Jun-2001: Change state to stage 27-May-2001: Generated from the SN/1 ******************************************/ %i %i %i %i /* functional circuits for the simulation */ %i %i %i %i /* R-type instructions |OP|r2|r3|r1| - | ... r1 <- r2 op r3 */ %d ADD 0x0 %d AND 0x1 %d SLT 0x3 %d NOT 0x4 %d SR 0x6 /* I-type instructions |OP|r1|r2| I | ... r1 <- r2(I) */ %d LD 0x8 %d ST 0x9 %d LDA 0xa %d RI 0xb %d IN 0xc %d OUT 0xd %d BZ 0xe %d BAL 0xf %d ITYPE op<15> %d OPCODE op<15:12> %d R2 op<11:10> %d R3 op<9:8> %d R1 op<7:6> %d IRSEL op<1:0> %d I 8#op<7> || op<7:0> declare snxcore { input inst<16> ; input datai<16> ; output datao<16> ; output iadrs<16> ; output adrs<16> ; instrin extint; instrout inst_read; instrout inst_write; instrout memory_read; instrout memory_write; } declare reg4 { input in<16> ; input inadr<2> ; input outadr<2> ; input outbadr<2> ; output out<16> ; output outb<16> ; instrin read; instrin readb; instrin write; instr_arg read(outadr); instr_arg readb(outbadr); instr_arg write(inadr,in); } module top { output adrs<16>; snxcore cpu; r1024_8 dram1,dram2,iram1,iram2; instruct cpu.inst_read cpu.inst = iram1.read(cpu.iadrs<9:0>).dout || iram2.read(cpu.iadrs<9:0>).dout ; instruct cpu.memory_read cpu.datai = dram1.read(cpu.adrs<9:0>).dout || dram2.read(cpu.adrs<9:0>).dout; instruct cpu.memory_write par { dram1.write(cpu.adrs<9:0>,cpu.datao<15:8>); dram2.write(cpu.adrs<9:0>,cpu.datao<7:0>); } instruct cpu.inst_write par { iram1.write(cpu.adrs<9:0>,cpu.datao<15:8>); iram2.write(cpu.adrs<9:0>,cpu.datao<7:0>); } } module snx2 { input inst<16> ; bidirect data<16> ; output iadrs<16> ; output adrs<16> ; instrin extint; instrout inst_read; instrout inst_write; instrout memory_read; instrout memory_write; snxcore cpu; instr_arg memory_write(adrs,data); instr_arg memory_read(adrs); instr_arg inst_read(iadrs); instruct cpu.inst_read cpu.inst = inst_read(cpu.iadrs).inst; instruct cpu.memory_read cpu.datai = memory_read(cpu.adrs).data; instruct cpu.memory_write memory_write(cpu.adrs,cpu.datao); } module snxcore { input inst<16> ; input datai<16> ; output datao<16> ; output iadrs<16> ; output adrs<16> ; instrin extint; instrself start; instrself targetif; instrout inst_read; instrout inst_write; instrout memory_read; instrout memory_write; reg pc<16> ; /* program counter */ reg_wr st0 ; /* power-on reset capable sequence registers */ reg st1 ; reg st2 ; /* stage registers */ inc16 inc ; cla16 cla ; reg4 gr; reg op<16> ; reg mar<16>, regnum<2>; sel dtop1<16>, dtop2<16>, br_taken, npc<16>; sel dADD, dAND, dRI, dSLT, dNOT, dSR, dLD, dST, dLDA, dIN, dOUT, dBZ, dBAL; sel_v aluo<16>; sel_v clain1<16>; instrself decode; instr_arg memory_write(adrs,datao); instr_arg memory_read(adrs); instr_arg inst_read(iadrs); stage_name int { task intt() ; } stage_name exec { task ift(pc) ; } stage_name memex { task store(mar,regnum); task load(mar,regnum); } /* Common operations for every stages must be described here */ par{ st0 := 0b1 ; st1 := st0; st2 := st1; any { (st2 == 0b0) & (st1 == 0b1): start(); } } instruct extint generate int.intt(); instruct start par { /* start instruction fetch */ generate exec.ift(0x0000); } instruct decode par { dADD=(OPCODE == ADD); dAND=(OPCODE == AND); dRI=(OPCODE == RI); dSLT=(OPCODE == SLT); dNOT=(OPCODE == NOT); dSR=(OPCODE == SR); dLD=(OPCODE == LD); dST=(OPCODE == ST); dLDA=(OPCODE == LDA); dIN=(OPCODE == IN); dOUT=(OPCODE == OUT); dBZ=(OPCODE == BZ); dBAL=(OPCODE == BAL); } stage int { state_name external_int; first_state external_int; state external_int finish; } stage exec { state_name ifetch, exe; first_state ifetch ; state ifetch par { op := inst_read(pc).inst; any { ^int.intt: goto exe; int.intt: relay exec.ift(0xfff0); } } state exe par { decode(); br_taken = dBAL | (dBZ & (dtop1 == 0x0000)); npc = inc.do(pc).out; any { br_taken:par { pc := aluo; goto ifetch; } dLD: par { relay memex.load(cla.out, R2); goto ifetch; } dST: par { relay memex.store(cla.out,R2) ; goto ifetch; } else: par { pc := npc; goto ifetch; } } /* any */ dtop1 = gr.read(R2).out; any { ITYPE: clain1 = I; else : clain1 = dtop1; } any { ITYPE & (R3 == 0b00):dtop2 = 0x0000; else :dtop2 = gr.readb(R3).outb; } any { (ITYPE | dADD): aluo = cla.do(0b0, clain1, dtop2).out; dSLT: par { cla.do(0b1, clain1, ^dtop2); aluo = 15#0b0 || ((clain1<15> & ^dtop2<15>)| (cla.out<15> & ^clain1<15> & ^dtop2<15>)| (cla.out<15> & clain1<15> & dtop2<15>)); } dAND : aluo = dtop1 & dtop2; dNOT : aluo = ^dtop1; dSR : aluo = 0b0 || dtop1<15:1> ; } any { ^ITYPE: gr.write(R1,aluo); dLDA : gr.write(R2, aluo); dBAL : gr.write(R2, npc); } /* any */ } /* par */ } /* stage */ stage memex { par { any { memex.store: memory_write(mar,gr.read(regnum).out); memex.load: gr.write(regnum, memory_read(mar).datai); } npc = inc.do(pc).out; relay exec.ift(npc); } } } /* module */ module reg4 { input in<16> ; input inadr<2> ; input outadr<2> ; input outbadr<2> ; output out<16> ; output outb<16> ; instrin read; instrin readb; instrin write; reg r0<16>,r1<16>,r2<16>,r3<16> ; instruct read any { outadr == 0b00: out = r0; outadr == 0b01: out = r1; outadr == 0b10: out = r2; outadr == 0b11: out = r3; } instruct readb any { outbadr == 0b00: outb = r0; outbadr == 0b01: outb = r1; outbadr == 0b10: outb = r2; outbadr == 0b11: outb = r3; } instruct write any { inadr == 0b00: r0 := in; inadr == 0b01: r1 := in; inadr == 0b10: r2 := in; inadr == 0b11: r3 := in; } }