Re: [myhdl-list] Python Hardware Processor
Brought to you by:
jandecaluwe
From: Norbo <Nor...@gm...> - 2012-03-04 12:08:43
|
Just got a bit further and i am now able to do function calls in the Python Hardware CPU, and a was able to reduce the logic usage of CPU a bit by shifting some registers into ram where the data needs an extra cycle be accessible. But still was able to maintain the one bytecode instruction per clk cycle execution. Now the cpu is able to execute python code like the following successfully (PORTA_IN,PORTB_IN and etc.. are the IO/Ports): With the following code the Cpu synthesises to approximatly 800 LUTS_4. (on lattice diamond 1.4 and Quartus web edition) I also needed to modify the bytecode a bit so that the functions are mapped correctly. Thereby i merge all the constants and all the globals of every function to a single place. (normaly every python function has its own constans memory and global name map) PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3} #need to start at 0 global_argument=2 def kate(Cycles,argx): global PORTC_OUT,PORTD_OUT x=0 PORTD_OUT=PORTD_OUT+argx while x<Cycles: x=x+1 PORTC_OUT=PORTC_OUT^8 return 2 def delay(Cycles1,Cycles2): global PORTC_OUT x=5 while x<(Cycles1+Cycles2): x=x+1 PORTC_OUT=PORTC_OUT^4 x=0 while x<kate(1,global_argument): PORTC_OUT=PORTC_OUT^2 x=x+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT # at least output ports need to be defined as gloabals x=0 a=7 b=8 var_argument_b=3 var_argument_b=var_argument_b+1 while 1: x=x+1 #funcas(kkt(3)) # TODO calling a function with an function as an argument would not work delay(global_argument,var_argument_b) if PORTA_IN==1: PORTC_OUT=PORTC_OUT^1 if x<20: PORTD_OUT=x elif 20<=x<25: #or x>=20 and x<25: #both works PORTD_OUT=(2**7)+x else: PORTD_OUT=x a,b=b,a PORTD_OUT=a<<1 Tried it on hardware and i was able to blink an led on a lattic pico development board. With the following python code: (The Output pin was connected to the 5. pin of PORTD_OUT.) The Synthesis tools says that it can be run at 23 Mhz or so but i was running it at 12 MHz. PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3} #need to start at 0 def wait(time): x=0 while x<100: td=0 x=x+1 while td<100: td=td+1 ss=0 while ss<time: ss=ss+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT while 1: PORTD_OUT=PORTD_OUT^16 wait(20) I just post the full code, right now its not very readable, ##################################### # File: pyHardwareCore.py # Author: Norbert Feurle # start Date: 2.2.2012 # latest Edit: 23.2.2012 # # Description: Python Hardware Processor # This Code implements a Hardware CPU in myhdl. The code for the CPU is drictly written in python # and since the hardware description is also in python, the programmcode is automatically loaded into the design # The cool thing is that with this approach only memory and stack hardware is allocated in Hardware which is # really needed. The Simulation of the cpu code on the hardware can be done in python only (only python needed! and of corse myhdl). # The bytecode of python is executed in the CPU with one instruction per cycle # You can simply instantiate more cores on an FPGA with different Programmcode to make them run in parallel # # License: Pro life licence. # You are not allowed to use this code for any purpose which is in any kind disrespectfully to life and/or freedom # In such a case it remains my property # for example: You are not allowed to build weapons, or large-scale animal husbandry automation equipment or anything # that is used to harm, destroy or is used to frighten living beeings at an unacceptable rate, or build hardware # with it where the workers dont get paid appropriate, or any process where the waste issue isnt solved in a sustainable way, # etc.. # If you use it respectfully you are allowed to use it for free and are welcome to contribute with your changes/extensions # You also have to keep this licence. ################################################################################################# ######################################################################################## #### Limitations: #### no lists, no dicts no tuples, no float, no complex numbers, etc. #### no classmembers,no multiplication, no exeptions, no for x in xxx:, etc. ######################################################################################## ### What is supported: #--------------------------------------------------- ### ints (with x bits), no other python types only plane ints ### if and while (comparisions with <,>, >=, <=,!=,== ) ### nested while loops up to CONST_LOOP_DEPTH (Constant Default value = 4) ### assignments to globals or local varibles from const, globals or define local variables ### Operators: +. -, ^ ,~, |, & ,<<,>> ### Simple Digital IOs over PORTS ### Function calls (with consts,and globals, or vars as argument, one intager as return value), no default arguments, no keyword arguments,no other functions as arguments ### up to MAX_NUMBER_FUNCTION_ARGUMENTS (Constant Default value = 10) arguments ### up to CONST_PC_STACK_DEPTH (Constant Default value=5) number of nested function calls ### up to VAR_MEM_DEPTH (Constant Default value=20) local variables ######################################################################################## ################################################################### ##### Bug Track / Upcomming Features list : #--------------------------------------------- # (done) Binary operations remove doesnt removes the operands from stack # (done but stack ram could be smaller) (but stack_mem is now very big, Solution -> add some cycles for rot_two, rot_three and rot_for and put stak into a RAM,maybe dualported ) dis.opmap['POP_BLOCK'] and dis.opmap['SETUP_LOOP'] clear stack # (halve done) Global memory initilisation in myhdl # (done)-> GLOBAL_CONTENT is set to (0,) in this case <- if there is no function exept CPU_main, toVHDL creates an error,probably because Global_mem is empty # (done) hasattr(eval(currentfunction.func_code.co_names[actual_Argument]), '__call__') througs exeption if PORTA_IN, etc is note defined global (defining PREDEFINED_IO_ADDRESSES should be enough) # (mostly done ) wheater make PORTS in a all positive range or all with -2**(x-1) to +2**(x-1) conversion from signed to unsigned # (done) Functions need to be able to use vars from var_mem as arguments (Dual ported var_mem) # TODO calling a function with an function as an argument would not work # TODO ROT_FOUR is not yet supported, adding a extra cycles is needed # TODO Test generated VHDL code, and on an FPGA, maybe cosimulation # TODO More Programm tests, Clean UP code, for example: eliminate magic numbers,general cleanup # (done) insert cycle after var_mem is read to make it possible to map it into ram, same for programm_code # TODO make jumps to addresses possible which exeed the size of VAR_BITWIDTH, for example to make a usable processor with WORD_SZ=4 bit # TODO generic addable multiplication support ########info: # ROT_TWO after SETUP_LOOP would not work but is kind of usless because the new stack block is empty ########################################## ################################################################# ####### Nice to haves: #----------------------------- # TODO maybe support List of ints with single integer subscription # TODO additional SPI,RS232,I2C,Timer,etc modules # TODO call functions from extern which are not loaded at startup # TODO dynamically generate I/O Ports on the processor dependend on PREDEFINED_IO_ADDRESSES ################################################################# ##### The main programm the cpu should execute #### PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3} #need to start at 0 global_argument=2 def kate(Cycles,argx): global PORTC_OUT,PORTD_OUT x=0 PORTD_OUT=PORTD_OUT+argx while x<Cycles: x=x+1 PORTC_OUT=PORTC_OUT^8 return 2 def delay(Cycles1,Cycles2): global PORTC_OUT x=5 while x<(Cycles1+Cycles2): x=x+1 PORTC_OUT=PORTC_OUT^4 x=0 while x<kate(1,global_argument): PORTC_OUT=PORTC_OUT^2 x=x+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT # at least output ports need to be defined as gloabals x=0 a=7 b=8 var_argument_b=3 var_argument_b=var_argument_b+1 while 1: x=x+1 #funcas(kkt(3)) # TODO calling a function with an function as an argument would not work delay(global_argument,var_argument_b) if PORTA_IN==1: PORTC_OUT=PORTC_OUT^1 if x<20: PORTD_OUT=x elif 20<=x<25: #x>=20 and x<25: #both work PORTD_OUT=(2**7)+x else: PORTD_OUT=x a,b=b,a PORTD_OUT=a<<1 def wait(time): x=0 while x<100: td=0 x=x+1 while td<100: td=td+1 ss=0 while ss<time: ss=ss+1 def CPU2_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT x=0 while 1: PORTD_OUT=PORTD_OUT^16 wait(20) if (PORTB_IN & 0x01)==1: PORTD_OUT=PORTD_OUT|0x20 else: PORTD_OUT=PORTD_OUT&0xdf #PORTD_OUT=PORTD_OUT^16 #PORTD_OUT=PORTD_OUT^16 #if (PORTA_IN & 0x01)==1: # PORTC_OUT=255 #else: # PORTC_OUT=0 ##### End of the main programm #### import MakeProcessorBytecode ProcessorCodeObject=MakeProcessorBytecode.MakeBytecode(CPU2_main,PREDEFINED_IO_ADDRESSES,globals()) #### Needed for the processor GLOBAL_FUNCTION_ADRESSES_START=ProcessorCodeObject.GLOBAL_FUNCTION_ADRESSES_START GLOBALS_MEM_CONTENT=ProcessorCodeObject.GLOBALS_MEM_CONTENT #tuple(GLOBALS_MEM_CONTENT) CONSTANTS_MEM_CONTENT=ProcessorCodeObject.CONSTANTS_MEM_CONTENT #tuple(CONSTANTS_MEM_CONTENT) COMPLETE_PROGRAMM_OPCODES=ProcessorCodeObject.COMPLETE_PROGRAMM_OPCODES #tuple(COMPLETE_PROGRAMM_OPCODES) COMPLETE_PROGRAMM_ARGS=ProcessorCodeObject.COMPLETE_PROGRAMM_ARGS #tuple(COMPLETE_PROGRAMM_ARGS) GLOBAL_OPCODE_ARG_MAX_VALUE=ProcessorCodeObject.GLOBAL_OPCODE_ARG_MAX_VALUE #max(COMPLETE_PROGRAMM_ARGS) GLOBAL_STACK_SIZE=ProcessorCodeObject.GLOBAL_STACK_SIZE ### get max stacksize ###### Start of the Processor myhdl implementation ############ from myhdl import * #import math def DP_RAM(dout, din, addr_wr,addr_rd, we, clk, WORD_SZ=8, DEPTH=16384): """ """ mem = [Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) for i in range(DEPTH)] @always(clk.posedge) def write_read(): if we: mem[int(addr_wr)].next = din dout.next = mem[int(addr_rd)] #@always_comb #def read(): return write_read def RAM(clk,dout,addr,CONTENT,WORD_SZ=8): Converttosigned_sig=Signal(intbv(0,min=dout.min*2,max=dout.max*2)) @always_comb def combi_log(): Converttosigned_sig.next=CONTENT[int(addr)] #workaround to allow greater than min to max range in positive be written to port @always(clk.posedge) def rom_logic(): dout.next= Converttosigned_sig[8:].signed() #CONTENT[int(addr)] return rom_logic,combi_log def ProgrammRAM(clk,rst,Opcode,Arg1,addr,OPCODE_CONTENT,OPCODE_ARGUMENTS_CONTENT): #OPCODE_MEM=PROGRAMM_CONTENT[0] #ARG_MEM=PROGRAMM_CONTENT[0] @always(clk.posedge) def progrom_logic(): #print "address:", addr Opcode.next= OPCODE_CONTENT[int(addr)] Arg1.next= OPCODE_ARGUMENTS_CONTENT[int(addr)] return progrom_logic GLOBAL_NUMBERSTACK_OPS=22 STACK_NOP,STACK_ADD,STACK_POSITIVE,STACK_NOT,STACK_NEGATIVE,STACK_INVERT,STACK_RSHIFT,STACK_LSHIFT,STACK_AND,STACK_SUB,STACK_OR,STACK_XOR,STACK_POP,STACK_LOAD,STACK_CMP,STACK_ROT_FOUR, STACK_ROT_TWO, STACK_ROT_THREE_0,STACK_ROT_THREE_1,STACK_DUP_TOP,STACK_SETUP_LOOP,STACK_POP_BLOCK=range(GLOBAL_NUMBERSTACK_OPS) def Stack(clk,rst,TopData_Out,Data_In,StackOP,CMPmode,WORD_SZ=32,SIZE=4): CONST_LOOP_DEPTH=5 #TODO magic number if SIZE<4: SIZE=4 Stack_mem = [Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) for i in range(SIZE*CONST_LOOP_DEPTH)] stack_read_addr=Signal(intbv(0,min=0,max=SIZE*CONST_LOOP_DEPTH)) stack_write_addr=Signal(intbv(0,min=0,max=SIZE*CONST_LOOP_DEPTH)) TOF_RAM_Data=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) Data_to_REG=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) #Data_to_REG_RD=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) REG_TopOfStack_Data=Signal(intbv(0,min=-2**(WORD_SZ-1),max=2**(WORD_SZ-1))) TOS_pointer=Signal(intbv(0,min=0,max=SIZE)) TOS_pointer_pre=Signal(intbv(0,min=0,max=SIZE)) #TOS3_pointer= Signal(intbv(0,min=0,max=SIZE)) REG_StackOP=Signal(intbv(0,min=0,max=GLOBAL_NUMBERSTACK_OPS)) REG_CmpMode=Signal(intbv(0,min=0,max=6)) enable_stackpointer_increase=Signal(bool(0)) enable_stackpointer_deacrease=Signal(bool(0)) enable_stack_write_data=Signal(bool(0)) stack_offset=Signal(intbv(0,min=0,max=SIZE*CONST_LOOP_DEPTH)) stack_pos_mem=[Signal(intbv(0,min=0,max=SIZE)) for i in range(CONST_LOOP_DEPTH+1)] stack_pos_mem_addr=Signal(intbv(0,min=0,max=CONST_LOOP_DEPTH+1)) SaveStack_pos=Signal(bool(0)) ReturnToStack_pos=Signal(bool(0)) #SaveStack_pos_function=Signal(bool(0)) @always(clk.posedge,rst.negedge) def seq_logic(): if rst == 0: TOS_pointer.next=0 stack_pos_mem_addr.next=0 stack_offset.next=0 REG_StackOP.next=STACK_NOP REG_CmpMode.next=0 else: if enable_stackpointer_increase: TOS_pointer.next=(TOS_pointer+1)%SIZE if enable_stackpointer_increase or enable_stack_write_data: Stack_mem[int(stack_write_addr)].next=Data_to_REG if enable_stackpointer_deacrease: TOS_pointer.next=(TOS_pointer-1)%SIZE if SaveStack_pos: #print "####### Save stack pos:",TOS_pointer stack_pos_mem[int(stack_pos_mem_addr)].next=TOS_pointer stack_pos_mem_addr.next=stack_pos_mem_addr+1 stack_offset.next=stack_offset+SIZE if ReturnToStack_pos: #print "####### Return stack pos:",TOS_pointer_pre TOS_pointer.next=TOS_pointer_pre stack_pos_mem_addr.next=stack_pos_mem_addr-1 stack_offset.next=stack_offset-SIZE TOS_pointer_pre.next=(stack_pos_mem[int(stack_pos_mem_addr-1)]) # if StackOP==STACK_LOAD: # REG_TopOfStack_Data.next=Data_In #else: REG_TopOfStack_Data.next=Data_to_REG REG_StackOP.next=StackOP REG_CmpMode.next= CMPmode TOF_RAM_Data.next=Stack_mem[int(stack_read_addr)] #@always_comb #def comb_logic2(): #TOS_Data_RD.next#=Stack_mem[int(TOS_pointer+stack_offset)] #TOS1_Data_RD.next=Stack_mem[int(TOS1_pointer+stack_offset)] #TOS2_Data_RD.next=Stack_mem[int(TOS2_pointer+stack_offset)] #TopData_Out.next=Data_to_REG #Stack_mem[int(TOS_pointer+stack_offset)] @always_comb def comb_logic(): #Data_to_REG_RD.next=REG_TopOfStack_Data stack_write_addr.next=TOS_pointer+stack_offset stack_read_addr.next=((TOS_pointer-1)%SIZE)+stack_offset #Data_to_stackmem.next=REG_TopOfStack_Data Data_to_REG.next=REG_TopOfStack_Data #TOS_Data.next=REG_TopOfStack_Data TopData_Out.next=REG_TopOfStack_Data #TopData_Out.next=0 SaveStack_pos.next=False ReturnToStack_pos.next=False enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=0 if REG_StackOP==STACK_LOAD: Data_to_REG.next=Data_In TopData_Out.next=Data_In elif REG_StackOP==STACK_POP: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data elif REG_StackOP==STACK_ADD: Data_to_REG.next=TOF_RAM_Data+REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data+REG_TopOfStack_Data elif REG_StackOP==STACK_POSITIVE: #??? Data_to_REG.next=REG_TopOfStack_Data TopData_Out.next=REG_TopOfStack_Data #TOS_Data.next=TOS_Data_RD elif REG_StackOP==STACK_NOT: Data_to_REG.next=not REG_TopOfStack_Data TopData_Out.next=not REG_TopOfStack_Data #TOS_Data.next=TOS_Data_RD elif REG_StackOP==STACK_NEGATIVE: Data_to_REG.next=-REG_TopOfStack_Data TopData_Out.next=-REG_TopOfStack_Data #TOS_Data.next=-TOS_Data_RD elif REG_StackOP==STACK_INVERT: Data_to_REG.next=~REG_TopOfStack_Data TopData_Out.next=~REG_TopOfStack_Data #TOS_Data.next=~TOS_Data_RD elif REG_StackOP==STACK_RSHIFT: Data_to_REG.next=TOF_RAM_Data>>REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data>>REG_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD>>TOS_Data_RD elif REG_StackOP==STACK_LSHIFT: Data_to_REG.next=TOF_RAM_Data<<REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data<<REG_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD<<TOS_Data_RD elif REG_StackOP==STACK_AND: Data_to_REG.next=TOF_RAM_Data®_TopOfStack_Data TopData_Out.next=TOF_RAM_Data®_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD&TOS_Data_RD elif REG_StackOP==STACK_SUB: Data_to_REG.next=TOF_RAM_Data-REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data-REG_TopOfStack_Data #TOS1_Data.next=TOS1_Data_RD-TOS_Data_RD elif REG_StackOP==STACK_OR: Data_to_REG.next=TOF_RAM_Data|REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data|REG_TopOfStack_Data elif REG_StackOP==STACK_XOR: Data_to_REG.next=TOF_RAM_Data^REG_TopOfStack_Data TopData_Out.next=TOF_RAM_Data^REG_TopOfStack_Data elif REG_StackOP==STACK_ROT_TWO: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data elif REG_StackOP==STACK_ROT_THREE_1: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data #elif REG_StackOP==STACK_DUP_TOP: # TopData_Out.next=REG_TopOfStack_Data #is standard assignment # Data_to_REG.next=REG_TopOfStack_Data elif REG_StackOP==STACK_POP_BLOCK: TopData_Out.next=TOF_RAM_Data Data_to_REG.next=TOF_RAM_Data elif REG_StackOP==STACK_CMP: if REG_CmpMode==0: #operator < if TOF_RAM_Data<REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==1: #operator <= if TOF_RAM_Data<=REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==2: #operator == if TOF_RAM_Data==REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==3: #operator != if TOF_RAM_Data!=REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==4: #operator > if TOF_RAM_Data>REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if REG_CmpMode==5: #operator >= if TOF_RAM_Data>=REG_TopOfStack_Data: Data_to_REG.next=1 TopData_Out.next=1 else: Data_to_REG.next=0 TopData_Out.next=0 if StackOP==STACK_NOP: enable_stackpointer_increase.next=0 elif StackOP==STACK_SETUP_LOOP: enable_stackpointer_increase.next=1 SaveStack_pos.next=True elif StackOP==STACK_POP_BLOCK: stack_read_addr.next=((TOS_pointer_pre)%SIZE)+(stack_offset-SIZE) enable_stackpointer_increase.next=0 ReturnToStack_pos.next=True elif StackOP==STACK_POSITIVE: #??? enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=TOS_Data_RD elif StackOP==STACK_NOT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=TOS_Data_RD elif StackOP==STACK_NEGATIVE: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=-TOS_Data_RD elif StackOP==STACK_INVERT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 #TOS_Data.next=~TOS_Data_RD elif StackOP==STACK_ADD: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD+TOS_Data_RD elif StackOP==STACK_RSHIFT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD>>TOS_Data_RD elif StackOP==STACK_LSHIFT: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD<<TOS_Data_RD elif StackOP==STACK_AND: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD&TOS_Data_RD elif StackOP==STACK_SUB: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD-TOS_Data_RD elif StackOP==STACK_OR: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD|TOS_Data_RD elif StackOP==STACK_XOR: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 #TOS1_Data.next=TOS1_Data_RD^TOS_Data_RD elif StackOP==STACK_POP: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=1 # elif StackOP==STACK_CALL_FUNCTION: # enable_stackpointer_increase.next=0 # enable_stackpointer_deacrease.next=1 #pop function address # SaveStack_pos_function.next=True elif StackOP==STACK_LOAD: enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 #TopOfStack_Data.next=Data_In elif StackOP==STACK_ROT_TWO: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=1 stack_write_addr.next=((TOS_pointer-1)%SIZE)+stack_offset #TOS_Data.next=TOS1_Data_RD #TOS1_Data.next=TOS_Data_RD elif StackOP==STACK_ROT_THREE_0: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=1 stack_write_addr.next=((TOS_pointer-2)%SIZE)+stack_offset stack_read_addr.next=((TOS_pointer-2)%SIZE)+stack_offset elif StackOP==STACK_ROT_THREE_1: enable_stackpointer_increase.next=0 enable_stackpointer_deacrease.next=0 enable_stack_write_data.next=1 Data_to_REG.next=TOF_RAM_Data stack_write_addr.next=((TOS_pointer-1)%SIZE)+stack_offset stack_read_addr.next=((TOS_pointer-1)%SIZE)+stack_offset #TOS_Data.next=TOS1_Data_RD #TOS1_Data.next=TOS2_Data_RD #TOS2_Data.next=TOS_Data_RD #elif StackOP==STACK_ROT_FOUR: ##TODO #TOS_Data.next=Stack_mem[int(TOS_pointer)] # TOS1_Data.next=Stack_mem[int(TOS1_pointer)] # TOS2_Data.next=Stack_mem[int(TOS2_pointer)] elif StackOP==STACK_DUP_TOP: enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 elif StackOP==STACK_CMP: enable_stackpointer_increase.next=1 enable_stackpointer_deacrease.next=0 else: enable_stackpointer_increase.next=0 return seq_logic,comb_logic#,comb_logic2 def IOModule(clk,rst,dout,din,addr,we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,GLOBAL_CONTENT,WIDTH=32): Sync_in1_PORTA=Signal(intbv(0)[WIDTH:]) Sync_in2_PORTA=Signal(intbv(0)[WIDTH:]) Sync_in1_PORTB=Signal(intbv(0)[WIDTH:]) Sync_in2_PORTB=Signal(intbv(0)[WIDTH:]) INTERN_PORTC_OUT=Signal(intbv(0)[WIDTH:]) INTERN_PORTD_OUT=Signal(intbv(0)[WIDTH:]) glob_mem = [Signal(intbv(0,min=-2**(WIDTH-1),max=2**(WIDTH-1))) for i in range(len(GLOBAL_CONTENT))] @always(clk.posedge,rst.negedge) def IO_write_sync(): if rst==0: INTERN_PORTC_OUT.next=0 INTERN_PORTD_OUT.next=0 for i in range(len(GLOBAL_CONTENT)): glob_mem[int(i)].next=GLOBAL_CONTENT[i] ##TODO this must be a memory initialisation else: Sync_in1_PORTA.next=PORTA_IN Sync_in2_PORTA.next=Sync_in1_PORTA Sync_in1_PORTB.next=PORTB_IN Sync_in2_PORTB.next=Sync_in1_PORTB if we: if addr==2: INTERN_PORTC_OUT.next=din[WIDTH:] elif addr==3: INTERN_PORTD_OUT.next=din[WIDTH:] elif addr>=4: glob_mem[int(addr-4)].next=din #GLOBAL_CONTENT[int(addr-4)] @always(clk.posedge) def IO_read(): PORTC_OUT.next=INTERN_PORTC_OUT PORTD_OUT.next=INTERN_PORTD_OUT dout.next = 0 if addr==0: dout.next = Sync_in2_PORTA[WIDTH:].signed() if addr==1: dout.next = Sync_in2_PORTB[WIDTH:].signed() if addr==2: dout.next = INTERN_PORTC_OUT[WIDTH:].signed() if addr==3: dout.next = INTERN_PORTD_OUT[WIDTH:].signed() if addr>=4: dout.next =glob_mem[int(addr-4)] return IO_write_sync,IO_read def Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,CPU_PROGRAM_OPCODES=COMPLETE_PROGRAMM_OPCODES,CPU_PROGRAM_ARGS=COMPLETE_PROGRAMM_ARGS,CPU_CONSTANTS=CONSTANTS_MEM_CONTENT,CPU_GLOBALS=GLOBALS_MEM_CONTENT,CONST_FUNCTION_ADRESSES_START=GLOBAL_FUNCTION_ADRESSES_START,VAR_BITWIDTH=32,VAR_MEM_DEPTH=20,STACK_SIZE=GLOBAL_STACK_SIZE,OPCODE_ARG_MAX_VALUE=GLOBAL_OPCODE_ARG_MAX_VALUE,DEBUG_OUTPUT=False): CONST_PROGRAMM_LENGTH=len(CPU_PROGRAM_OPCODES) NUMBER_OF_SELECTS=4 ENUM_SEL_NONE,ENUM_SEL_VARIABLE,ENUM_SEL_CONST,ENUM_SEL_GLOBAL=range(NUMBER_OF_SELECTS) StackTopSel=Signal(intbv(0,min=0,max=NUMBER_OF_SELECTS)) REG_StackTopSel=Signal(intbv(0,min=0,max=NUMBER_OF_SELECTS)) NUMBER_FROM_SELECTS=4 FROM_NONE,FROM_CONST,FROM_GLOBAL,FROM_VAR=range(NUMBER_FROM_SELECTS) argnext_store=Signal(intbv(0,min=0,max=NUMBER_FROM_SELECTS)) REG_argnext_store=Signal(intbv(0,min=0,max=NUMBER_FROM_SELECTS)) #### helping signals MAX_NUMBER_FUNCTION_ARGUMENTS=10 #TODO magic number #EnableJump=Signal(bool(0)) Inc_ArgumentCount=Signal(bool(0)) Clear_ArgumentCount=Signal(bool(0)) REG_ArgumentCount=Signal(intbv(0,min=0,max=MAX_NUMBER_FUNCTION_ARGUMENTS+2)) JumpValue=Signal(intbv(0)[8:]) MAX_SUB_CYCLES=2 REG_sub_pc_count=Signal(intbv(0,min=0,max=MAX_SUB_CYCLES)) sub_pc_count_next=Signal(intbv(0,min=0,max=MAX_SUB_CYCLES)) Push_Programcounter=Signal(bool(0)) Pop_Programcounter=Signal(bool(0)) Old_ProgrammCounter=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) REG_PC_offsetValue=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) PC_offsetValue=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) Old_PC_offsetValue=Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) Set_Variables_offset=Signal(bool(0)) #Return_Variables_offset=Signal(bool(0)) #### Programm Memory Signals Opcode=Signal(intbv(0)[8:]) Arg1=Signal(intbv(0,min=0,max=OPCODE_ARG_MAX_VALUE+1)) REG_ProgramCounter=Signal(intbv(-1,min=-1,max=CONST_PROGRAMM_LENGTH+1)) #### Constants Memory Signals ConstantsData=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) ConstantsAddr=Signal(intbv(0,min=0,max=len(CPU_CONSTANTS))) #### Programm Variables RAM Signals Varibles_DataOut=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) Variables_DataIn=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) VariablesAddr=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) VariablesAddr_write_to_inst=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) VariablesAddr_read_to_inst=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) REG_max_Variables_address=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) Old_max_Variables_address=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) REG_Variables_addr_offset=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) Old_Variables_addr_offset=Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) Variables_we=Signal(bool(0)) #### Stack Signals # STACK_SIZE Stack_DataIn=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) StackValue0=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) StackOP=Signal(intbv(0,min=0,max=GLOBAL_NUMBERSTACK_OPS)) StackOP_CMPmode=Signal(intbv(0,min=0,max=6)) #### IO Module Signals NR_IO_ADDRESSES=4 # TODO magic number IO_MODULE_LENGTH_MAX=NR_IO_ADDRESSES+len(GLOBALS_MEM_CONTENT)+1 CONST_FUNCTION_ADRESSES_START # <-- is a parameter of the processor unit IO_DataOut=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) IO_DataIn=Signal(intbv(0,min=-2**(VAR_BITWIDTH-1),max=2**(VAR_BITWIDTH-1))) #Signal(intbv(0)[VAR_BITWIDTH:]) IO_addr=Signal(intbv(0,min=0,max=IO_MODULE_LENGTH_MAX)) IO_we=Signal(bool(0)) ####Variables RAM instantiation VariablesRAM_inst=DP_RAM(Varibles_DataOut, Variables_DataIn, VariablesAddr_write_to_inst,VariablesAddr_read_to_inst, Variables_we, clk, WORD_SZ=VAR_BITWIDTH, DEPTH=VAR_MEM_DEPTH) ###Programm Code Memory instantiation ProgrammCode_inst=ProgrammRAM(clk,rst,Opcode,Arg1,JumpValue,OPCODE_CONTENT=CPU_PROGRAM_OPCODES,OPCODE_ARGUMENTS_CONTENT=CPU_PROGRAM_ARGS) ###Constants memory instantiation ConstantsRAM_inst=RAM(clk,ConstantsData,ConstantsAddr,CPU_CONSTANTS,WORD_SZ=VAR_BITWIDTH) ###The stack TheStack_inst=Stack(clk,rst,StackValue0,Stack_DataIn,StackOP,StackOP_CMPmode, WORD_SZ=VAR_BITWIDTH,SIZE=STACK_SIZE) ###I/O Module instantiation IOModule_inst=IOModule(clk,rst,IO_DataOut,IO_DataIn,IO_addr,IO_we,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,GLOBAL_CONTENT=CPU_GLOBALS,WIDTH=VAR_BITWIDTH) CONST_PC_STACK_DEPTH=5 #Defines how many nasted function are possible TODO magic number REG_pc_stack_addr=Signal(intbv(0,min=0,max=CONST_PC_STACK_DEPTH)) pc_steck_mem = [Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) for i in range(CONST_PC_STACK_DEPTH)] pc_offsets_mem = [Signal(intbv(0,min=0,max=CONST_PROGRAMM_LENGTH+1)) for i in range(CONST_PC_STACK_DEPTH)] max_var_addr_mem=[Signal(intbv(0,min=0,max=VAR_MEM_DEPTH)) for i in range(CONST_PC_STACK_DEPTH)] @always(clk.posedge,rst.negedge) def seq_logic(): if rst == 0: ##### REG_ProgramCounter Part ######## REG_ProgramCounter.next = -1 #TODO very not nice ##### END REG_ProgramCounter Part ######## REG_ArgumentCount.next=0 REG_max_Variables_address.next=0 REG_Variables_addr_offset.next=0 REG_pc_stack_addr.next=0 REG_PC_offsetValue.next=0 REG_StackTopSel.next=ENUM_SEL_NONE REG_sub_pc_count.next=0 else: if Inc_ArgumentCount==True: REG_ArgumentCount.next=REG_ArgumentCount+1 if Clear_ArgumentCount==True: REG_ArgumentCount.next=0 if VariablesAddr_write_to_inst>=REG_max_Variables_address: REG_max_Variables_address.next=VariablesAddr_write_to_inst+1 #print "REG_max_Variables_address",REG_max_Variables_address REG_StackTopSel.next=StackTopSel REG_argnext_store.next=argnext_store ##### REG_ProgramCounter Part ######## #if EnableJump==True: REG_ProgramCounter.next=JumpValue #else: # REG_ProgramCounter.next = REG_ProgramCounter+1 REG_PC_offsetValue.next=PC_offsetValue ##### END REG_ProgramCounter Part ######## REG_sub_pc_count.next=sub_pc_count_next ##### Programmm counter stack####### if Push_Programcounter: # Set at CALL_FUNCTION pc_steck_mem[int(REG_pc_stack_addr-1)].next=REG_ProgramCounter pc_offsets_mem[int(REG_pc_stack_addr-1)].next=REG_PC_offsetValue if Pop_Programcounter: # Set at RETURN_VALUE REG_pc_stack_addr.next=REG_pc_stack_addr-1 REG_Variables_addr_offset.next=Old_Variables_addr_offset REG_max_Variables_address.next=Old_max_Variables_address #print "########returning REG_max_Variables_address:", REG_max_Variables_address,Old_max_Variables_address,Old_Variables_addr_offset #####End Programmm counter stack######### if Set_Variables_offset: # Set at LOAD_GLOBAL if a function address is loaded REG_pc_stack_addr.next=REG_pc_stack_addr+1 max_var_addr_mem[int(REG_pc_stack_addr)].next=REG_max_Variables_address REG_Variables_addr_offset.next=REG_max_Variables_address #print "###########LOAD_GLOBAL",REG_Variables_addr_offset, REG_max_Variables_address,REG_ProgramCounter,JumpValue #if Return_Variables_offset: @always_comb def comb_logic2(): VariablesAddr_write_to_inst.next=REG_Variables_addr_offset+VariablesAddr #print "VariablesAddr",VariablesAddr, "REG_Variables_addr_offset",REG_Variables_addr_offset Old_ProgrammCounter.next=0 Old_max_Variables_address.next=0 Old_Variables_addr_offset.next=0 Old_PC_offsetValue.next=0 if REG_pc_stack_addr>0: Old_PC_offsetValue.next=pc_offsets_mem[int(REG_pc_stack_addr-1)] Old_ProgrammCounter.next=pc_steck_mem[int(REG_pc_stack_addr-1)] Old_max_Variables_address.next=max_var_addr_mem[int(REG_pc_stack_addr-1)] if REG_pc_stack_addr>1: Old_Variables_addr_offset.next=max_var_addr_mem[int(REG_pc_stack_addr-2)] ##### Opcode handling############# @always_comb def comb_logic(): sub_pc_count_next.next=0 VariablesAddr_read_to_inst.next=VariablesAddr_write_to_inst #Enable_PC_offset.next=False PC_offsetValue.next=REG_PC_offsetValue Set_Variables_offset.next=False #Return_Variables_offset.next=False Push_Programcounter.next=False Pop_Programcounter.next=False Inc_ArgumentCount.next=False Clear_ArgumentCount.next=False #EnableJump.next=False JumpValue.next=REG_ProgramCounter+1 ConstantsAddr.next=0 StackOP.next=STACK_NOP StackOP_CMPmode.next=0 Stack_DataIn.next=0 Variables_we.next=False VariablesAddr.next=0 Variables_DataIn.next=StackValue0 IO_we.next=False IO_addr.next=0 IO_DataIn.next=StackValue0 StackTopSel.next=ENUM_SEL_NONE if REG_StackTopSel==ENUM_SEL_CONST: Stack_DataIn.next=ConstantsData elif REG_StackTopSel==ENUM_SEL_GLOBAL: Stack_DataIn.next=IO_DataOut elif REG_StackTopSel==ENUM_SEL_VARIABLE: Stack_DataIn.next=Varibles_DataOut elif REG_StackTopSel==ENUM_SEL_NONE: Stack_DataIn.next=0 argnext_store.next=FROM_NONE if REG_argnext_store==FROM_GLOBAL: VariablesAddr.next=REG_ArgumentCount-2 Variables_DataIn.next=IO_DataOut Variables_we.next=True elif REG_argnext_store==FROM_VAR: VariablesAddr.next=REG_ArgumentCount-2 Variables_DataIn.next=Varibles_DataOut Variables_we.next=True elif REG_argnext_store==FROM_CONST: VariablesAddr.next=REG_ArgumentCount-2 Variables_DataIn.next=ConstantsData Variables_we.next=True if Opcode==23: #dis.opmap['BINARY_ADD']: # 23, StackOP.next=STACK_ADD elif Opcode==64: #dis.opmap['BINARY_AND']: # 64, StackOP.next=STACK_ADD elif Opcode==62: #dis.opmap['BINARY_LSHIFT']: #: 62, StackOP.next=STACK_LSHIFT elif Opcode==66: #dis.opmap['BINARY_OR']: #: 66, StackOP.next=STACK_OR elif Opcode==63: #dis.opmap['BINARY_RSHIFT']: #: 63, StackOP.next=STACK_RSHIFT elif Opcode==24: #dis.opmap['BINARY_SUBTRACT']: #: 24, StackOP.next=STACK_SUB elif Opcode==65: #dis.opmap['BINARY_XOR']: #: 65, StackOP.next=STACK_XOR elif Opcode==107: #dis.opmap['COMPARE_OP']: #: 107, StackOP.next=STACK_CMP StackOP_CMPmode.next=Arg1 elif Opcode==4: #dis.opmap[''DUP_TOP']: # 4 StackOP.next=STACK_DUP_TOP elif Opcode==113: #dis.opmap['JUMP_ABSOLUTE'] : #: 113, #EnableJump.next=True JumpValue.next=Arg1+REG_PC_offsetValue elif Opcode==110: #dis.opmap['JUMP_FORWARD']: #: 110, #EnableJump.next=True #print "JUMP_FORWARD" JumpValue.next=REG_ProgramCounter+1+Arg1 #relative jump elif Opcode==111: #dis.opmap['JUMP_IF_FALSE_OR_POP']: #: 111, if StackValue0[1:0]==0: #EnableJump.next=True JumpValue.next=Arg1+REG_PC_offsetValue else: StackOP.next=STACK_POP elif Opcode==112: #dis.opmap['JUMP_IF_TRUE_OR_POP']: #: 112, if StackValue0[1:0]==1: JumpValue.next=Arg1+REG_PC_offsetValue #EnableJump.next=True else: StackOP.next=STACK_POP elif Opcode==100: #dis.opmap['LOAD_CONST']: #: 100, if REG_ArgumentCount==0: StackOP.next=STACK_LOAD StackTopSel.next=ENUM_SEL_CONST ConstantsAddr.next=Arg1 else: Inc_ArgumentCount.next=True ConstantsAddr.next=Arg1 argnext_store.next=FROM_CONST elif Opcode==124: #dis.opmap['LOAD_FAST']: #: 124, #TODO Split read and write address to support var arguments if REG_ArgumentCount==0: StackOP.next=STACK_LOAD VariablesAddr.next=Arg1 StackTopSel.next=ENUM_SEL_VARIABLE else: Inc_ArgumentCount.next=True VariablesAddr_read_to_inst.next=Old_Variables_addr_offset+Arg1 argnext_store.next=FROM_VAR elif Opcode==116: #dis.opmap['LOAD_GLOBAL']: #116, if Arg1>=CONST_FUNCTION_ADRESSES_START: Inc_ArgumentCount.next=True Set_Variables_offset.next=True if REG_ArgumentCount==0: # load from global mem StackOP.next=STACK_LOAD IO_addr.next=Arg1 StackTopSel.next=ENUM_SEL_GLOBAL else: Inc_ArgumentCount.next=True IO_addr.next=Arg1 argnext_store.next=FROM_GLOBAL elif Opcode==131: #dis.opmap['CALL_FUNCTION'] #print "############### Call Function ##########" Push_Programcounter.next=True #Enable_PC_offset.next=True JumpValue.next=StackValue0 PC_offsetValue.next=StackValue0 #Put on the stack with LOAD_GLOBAL StackOP.next=STACK_POP # The Function Arguments are not loaded over the stack # they are written directly to the Variables RAM if the LOAD_GLOBAL argument is in the Function address range Clear_ArgumentCount.next=True elif Opcode==83: #dis.opmap['RETURN_VALUE'] #print "############### Return Function ##########" #Enable_PC_offset.next=True PC_offsetValue.next=Old_PC_offsetValue JumpValue.next=Old_ProgrammCounter+1 Pop_Programcounter.next=True #StackOP.next=STACK_POP_BLOCK elif Opcode==97: #dis.opmap['STORE_GLOBAL']: 97, IO_we.next=True IO_addr.next=Arg1 StackOP.next=STACK_POP elif Opcode==114: #dis.opmap['POP_JUMP_IF_FALSE']: #: 114, StackOP.next=STACK_POP if StackValue0[1:0]==0: JumpValue.next=Arg1+REG_PC_offsetValue #EnableJump.next=True elif Opcode==115: #dis.opmap['POP_JUMP_IF_TRUE']: #: 115, StackOP.next=STACK_POP if StackValue0[1:0]==1: JumpValue.next=Arg1+REG_PC_offsetValue #EnableJump.next=True elif Opcode==1: #dis.opmap['POP_TOP'] StackOP.next=STACK_POP elif Opcode==5: #dis.opmap['ROT_FOUR']: #: 5, StackOP.next=STACK_ROT_FOUR elif Opcode==3: #dis.opmap['ROT_THREE']: #: 3, if REG_sub_pc_count==0: sub_pc_count_next.next=REG_sub_pc_count+1 JumpValue.next=REG_ProgramCounter StackOP.next=STACK_ROT_THREE_0 if REG_sub_pc_count==1: sub_pc_count_next.next=0 StackOP.next=STACK_ROT_THREE_1 elif Opcode==2: #dis.opmap['ROT_TWO']: #: 2, StackOP.next=STACK_ROT_TWO elif Opcode==125: #dis.opmap['STORE_FAST']: #: 125, Variables_we.next=True VariablesAddr.next=Arg1 StackOP.next=STACK_POP elif Opcode==15: #dis.opmap['UNARY_INVERT']: #:15 StackOP.next=STACK_INVERT elif Opcode==11: #dis.opmap['UNARY_NEGATIVE']: #: 11, StackOP.next=STACK_NEGATIVE elif Opcode==12: #dis.opmap['UNARY_NOT']: #: 12, StackOP.next=STACK_NOT elif Opcode==10: #dis.opmap['UNARY_POSITIVE']: #: 10, StackOP.next=STACK_POSITIVE elif Opcode==120: #dis.opmap['SETUP_LOOP']: # TODO?? #(explanation from python homepage) Pushes a block for a loop onto the block stack. The block spans from the current instruction with a size of delta bytes. StackOP.next=STACK_SETUP_LOOP #print "##########setup loop" elif Opcode==87: #dis.opmap['POP_BLOCK']: # TODO?? dis.opmap['POP_BLOCK'] StackOP.next=STACK_POP_BLOCK #print "##########pop block" else: StackOP.next=STACK_NOP #raise ValueError("Unsuported Command:"+str(Opcode)) #if rst!=0: print "Comand not supported:",Opcode if DEBUG_OUTPUT: import dis cmp_op = dis.cmp_op hasconst = dis.hasconst hasname = dis.hasname hasjrel = dis.hasjrel haslocal = dis.haslocal hascompare = dis.hascompare @always(Opcode,Arg1) def monitor_opcode(): instruction = (dis.opname[int(Opcode)]+" "+str(int(Opcode)), None, None, None) if Opcode in hasconst: instruction = (instruction[0],int(Arg1) ,'const=', CPU_CONSTANTS[Arg1]) elif Opcode in hasname: #if Arg1>NR_IO_ADDRESSES: # instruction = (instruction[0],Arg1 ,'global=', CPU_GLOBALS[Arg1]) #else: instruction = (instruction[0],int(Arg1) ,None, None) #print "Error: no name instruction is supported yet" #raise StopSimulation elif Opcode in hasjrel: instruction = (instruction[0], int(Arg1),'addr=', REG_ProgramCounter+Arg1) elif Opcode in haslocal: instruction = (instruction[0], int(Arg1),'var=', int(Varibles_DataOut.val)) elif Opcode in hascompare: instruction = (instruction[0], int(Arg1),'cmp=', cmp_op[Arg1]) print instruction if DEBUG_OUTPUT: return seq_logic,comb_logic,comb_logic2,VariablesRAM_inst,ProgrammCode_inst,ConstantsRAM_inst,TheStack_inst,IOModule_inst,monitor_opcode else: return seq_logic,comb_logic,comb_logic2,VariablesRAM_inst,ProgrammCode_inst,ConstantsRAM_inst,TheStack_inst,IOModule_inst #,monitor_opcode def Processor_TESTBENCH(): WORD_SZ=8 rst, clk = [Signal(bool(0)) for i in range(2)] PORTA_IN=Signal(intbv(0)[WORD_SZ:]) PORTB_IN=Signal(intbv(0)[WORD_SZ:]) PORTC_OUT=Signal(intbv(0)[WORD_SZ:]) PORTD_OUT=Signal(intbv(0)[WORD_SZ:]) toVHDL(Processor,clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ) Processor_inst=Processor(clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ,DEBUG_OUTPUT=False) @always(delay(10)) def clkgen(): clk.next = not clk @instance def stimulus(): print "Reseting ########" rst.next=0 print "Setting PORTA_IN too 0 ########" PORTA_IN.next=0 for i in range(3): yield clk.negedge print "Release Reset ########" rst.next=1 for i in range(200): yield clk.negedge print "Setting PORTA_IN too 1 (PORTC bit 0 should toggle) ########" PORTA_IN.next=1 for i in range(2000): yield clk.negedge print "Setting PORTA_IN too 0 (PORTC bit 0 should stop toggling) ########" PORTA_IN.next=0 for i in range(2000): yield clk.negedge raise StopSimulation @instance def Monitor_PORTC(): print "\t\tPortC:",PORTC_OUT,"Binary:" ,bin(PORTC_OUT,WORD_SZ) ##TODO bin is not supported in simulation while 1: yield PORTC_OUT print "\t\tPortC:",PORTC_OUT,"Binary:" ,bin(PORTC_OUT,WORD_SZ) @instance def Monitor_PORTD(): print "PortD:",PORTD_OUT while 1: yield PORTD_OUT print "PortD:",PORTD_OUT return clkgen,Processor_inst,stimulus,Monitor_PORTC,Monitor_PORTD def ClkSysClk(clk_intern): @always(clk_intern) def logic(): # do nothing here pass clk_intern.driven="wire" __vhdl__="""OSCInst0: OSCH -- synthesis translate_off GENERIC MAP ( NOM_FREQ => "2.08" ) -- synthesis translate_on PORT MAP ( STDBY=> '0', OSC=> %(clk_intern)s);""" return logic def PicoBoard(iPushBn,rst, iCap_btn1,iCap_btn2,iCap_btn3,iCap_btn4, oLCD_COM0,oLCD_COM1,oLCD_COM2,oLCD_COM3,oLCD_5,oLCD_6,oLCD_7,oLCD_8,oLCD_9,oLCD_10,oLCD_11,oLCD_12, iUart_rx,oUart_tx, oSpi_sclk,oSpi_csn,oSpi_mosi,iSpi_miso, ioScl,ioSda, oI2CAlert,oEnAMP,oEnTempSPI, Icc_analog_cmp_n,iIcc_analog_cmp_p,oIcc_analog_out,iIcco_analog_cmp_n,iIcco_analog_cmp_p,oIcco_analog_out, iClk_USB,oUSBorBattout,oTouched1out): WORD_SZ=8 #rst, clk = [Signal(bool(0)) for i in range(2)] clk_intern=Signal(bool(0)) btn_rst=Signal(bool(0)) #nRst=Signal(bool(0)) PORTA_IN=Signal(intbv(0)[WORD_SZ:]) PORTB_IN=Signal(intbv(0)[WORD_SZ:]) PORTC_OUT=Signal(intbv(0)[WORD_SZ:]) PORTD_OUT=Signal(intbv(0)[WORD_SZ:]) #counter=Signal(intbv(0,min=0,max=12000000)) #tog=Signal(bool(0)) Processor_inst=Processor(iClk_USB,btn_rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ,DEBUG_OUTPUT=False) #@always(iClk_USB.posedge) #def seqen_logic(): # counter.next=(counter+1)%12000000 # if counter==0: # tog.next=not tog # oUSBorBattout.next=tog # Clk_inst=ClkSysClk(clk_intern) #connect processor to outside world @always_comb def combo_logic(): PORTB_IN[0].next=iCap_btn1 PORTB_IN[1].next=iCap_btn2 PORTB_IN[3].next=iCap_btn3 PORTB_IN[4].next=iCap_btn4 #PORTA_IN[0].next=iPushBn btn_rst.next=iPushBn oLCD_5.next=PORTC_OUT[0] oLCD_6.next=PORTC_OUT[1] oLCD_7.next=PORTC_OUT[2] oLCD_8.next=PORTC_OUT[3] oLCD_9.next=PORTC_OUT[4] oLCD_10.next=PORTC_OUT[5] oLCD_11.next=PORTC_OUT[6] oLCD_12.next=PORTC_OUT[7] oLCD_COM0.next=PORTD_OUT[0] oLCD_COM1.next=PORTD_OUT[1] oLCD_COM2.next=PORTD_OUT[2] oLCD_COM3.next=PORTD_OUT[3] oUart_tx.next=0 oSpi_sclk.next=0 oSpi_csn.next=0 oSpi_mosi.next=0 ioScl.next=0 ioSda.next=0 oI2CAlert.next=0 oEnAMP.next=0 oEnTempSPI.next=0 oIcc_analog_out.next=0 oIcco_analog_out.next=0 oTouched1out.next=PORTD_OUT[4] oUSBorBattout.next=PORTD_OUT[5] return Processor_inst,combo_logic#,seqen_logic #,Clk_inst ##################### convert pico Board to VHDL################### NumberArguments=38 for i in range(NumberArguments): code="A"+str(i)+"= Signal(bool(0))" exec(code) code="toVHDL(PicoBoard" for i in range(NumberArguments): code=code+",A"+str(i) code=code+")" exec(code) ##################### convert pico Board to VHDL################### #toVHDL(Processor,clk,rst,PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,VAR_BITWIDTH=WORD_SZ) #toVHDL(Processor_TESTBENCH) #tb = traceSignals(Processor_TESTBENCH) sim = Simulation(Processor_TESTBENCH()) #sim = Simulation(tb) sim.run() #def convert(): # WORD_SZ=8 # DEPTH=16384 # we, clk = [Signal(bool(0)) for i in range(2)] # dout = Signal(intbv(0)[WORD_SZ:]) # din = Signal(intbv(0)[WORD_SZ:]) # addr = Signal(intbv(0)[16:]) # toVHDL(RAM, dout, din, addr, we,clk,WORD_SZ,DEPTH) #convert() #def simulate(timesteps): # tb = traceSignals(test_dffa) # sim = Simulation(tb) # sim.run(timesteps) #simulate(20000) And the MakeProcessorBytecode Module: import dis ################# Reworking the bytecode, so that it better fits into the Processor (e.g Alignment issues)################### class MakeBytecode: def __init__(self,mainfunction,PredefinedIOAddresses,OtherGlobals): for Portname in PredefinedIOAddresses.keys(): OtherGlobals[Portname]=0 Unworked_functionArray={mainfunction.func_name:mainfunction} occuring_globals_dict=PredefinedIOAddresses Processed_functions_dict={} function_names_inorder=[] Function_offset=0 programm_dict={} while len(Unworked_functionArray)>0: funcname,currentfunction=Unworked_functionArray.popitem() Processed_functions_dict[funcname]=(Function_offset,currentfunction) #create function mapping in Programm Rom (start addresses of functions) function_names_inorder.append(funcname) theprogramm=tuple([ord(i) for i in currentfunction.func_code.co_code]) # count=0 new_count=0 REWORKED_GLOBAL_PROGRAMM_OPCODE=[] REWORKED_GLOBAL_PROGRAMM_ARG=[] Addressmap_old_new={} # create a seperate opcode and argument List (fits better in myhdl ram) # extend opcodes without argument with an 0 argument while 1: if count<len(theprogramm): REWORKED_GLOBAL_PROGRAMM_OPCODE.append(theprogramm[count]) Addressmap_old_new[count]=new_count if theprogramm[count]>=dis.HAVE_ARGUMENT: actual_Argument=(theprogramm[count+2]<<8)+theprogramm[count+1] REWORKED_GLOBAL_PROGRAMM_ARG.append(actual_Argument) if theprogramm[count]==dis.opmap['LOAD_GLOBAL']: if hasattr(OtherGlobals[currentfunction.func_code.co_names[actual_Argument]], '__call__'): # if GLOBAL_LOAD loads a function if not Processed_functions_dict.has_key(currentfunction.func_code.co_names[actual_Argument]): #if function is allready processed ##every function is just added once because it is a dictionary Unworked_functionArray[currentfunction.func_code.co_names[actual_Argument]]=OtherGlobals[currentfunction.func_code.co_names[actual_Argument]] count=count+3 else: REWORKED_GLOBAL_PROGRAMM_ARG.append(0) count=count+1 new_count=new_count+1 else: break Function_offset=Function_offset+len(REWORKED_GLOBAL_PROGRAMM_OPCODE) # next function will get next free Programm ROM Address # Readjust all absolute jump addresses for index,i in enumerate(REWORKED_GLOBAL_PROGRAMM_OPCODE): if i in dis.hasjabs: REWORKED_GLOBAL_PROGRAMM_ARG[index]=Addressmap_old_new[REWORKED_GLOBAL_PROGRAMM_ARG[index]] # Readjust relative jump addresses, for now only JUMP_FORWARD is changed count=0 while 1: if count<len(theprogramm): if theprogramm[count]>=dis.HAVE_ARGUMENT: actual_Argument=(theprogramm[count+2]<<8)+theprogramm[count+1] if theprogramm[count]==dis.opmap['JUMP_FORWARD']: #print count REWORKED_GLOBAL_PROGRAMM_ARG[Addressmap_old_new[count]]=Addressmap_old_new[count+3+actual_Argument]-Addressmap_old_new[count+3] count=count+3 else: count=count+1 else: break programm_dict[funcname]=(REWORKED_GLOBAL_PROGRAMM_OPCODE,REWORKED_GLOBAL_PROGRAMM_ARG) ## after this: Every Opcode and argument is at one address, Absolut jumps are corrected, and relative JUMP_FORWARD is corrected ########## end while len(Unworked_functionArray)>0: ######### #occuring_globals_dict=PREDEFINED_IO_ADDRESSES self.GLOBALS_MEM_CONTENT=[] if len(occuring_globals_dict)>0: globals_addr=max(occuring_globals_dict.values())+1 else: globals_addr=0 occuring_const_values_dict={} self.CONSTANTS_MEM_CONTENT=[] if len(occuring_const_values_dict)>0: const_addr=max(occuring_const_values_dict.values())+1 else: const_addr=0 ### Adjust and merge LOAD_GLOBAL, STORE_GLOBAL,LOAD_CONST , and Global_mem ##create shared GLOBALS_MEM_CONTENT and shared CONSTANTS_MEM_CONTENT ###merge constants (because python creates uniqe constants for every function) ###merge globals (introduce global_var_mem, only for function calling and global constants) ###rework global addresses (LOAD_GLOBAL, STORE_GLOBAL) ###rework const addresses (LOAD_CONST) ###rework absolut jump addresses of functions (LOAD_GLOBAL) ###only constant arguments are supported, or dual ported var mem is needed list_Load_global_when_fcall=[] for funcname in function_names_inorder: currentprogramm_opcodes=programm_dict[funcname][0] currentprogramm_arg=programm_dict[funcname][1] for index,i in enumerate(currentprogramm_opcodes): if i==dis.opmap['LOAD_CONST']: const_value=Processed_functions_dict[funcname][1].func_code.co_consts[currentprogramm_arg[index]] if type(const_value)==type(0): if not occuring_const_values_dict.has_key(const_value): self.CONSTANTS_MEM_CONTENT.append(const_value) occuring_const_values_dict[const_value]=const_addr const_addr=const_addr+1 currentprogramm_arg[index]=occuring_const_values_dict[const_value] elif type(const_value)==type(None) and currentprogramm_arg[index]==0: pass else: print "Error: Only integers are suportted, Type is:",type(const_value) if i==dis.opmap['LOAD_GLOBAL'] or i==dis.opmap['STORE_GLOBAL']: global_name=Processed_functions_dict[funcname][1].func_code.co_names[currentprogramm_arg[index]] if type(OtherGlobals[global_name])==type(0): ##needs to be an integer if not occuring_globals_dict.has_key(global_name): occuring_globals_dict[global_name]=globals_addr self.GLOBALS_MEM_CONTENT.append(OtherGlobals[global_name]) globals_addr=globals_addr+1 currentprogramm_arg[index]=occuring_globals_dict[global_name] elif i==dis.opmap['LOAD_GLOBAL'] and hasattr(OtherGlobals[global_name], '__call__'): list_Load_global_when_fcall.append((funcname,global_name,index)) else: print "Error: Only integers are suportted, Type is:",type(OtherGlobals[global_name]) #store changes programm_dict[funcname]=(currentprogramm_opcodes,currentprogramm_arg) #print occuring_globals_dict #print "ops:",currentprogramm_opcodes #print "args:",currentprogramm_arg self.GLOBAL_FUNCTION_ADRESSES_START=globals_addr ##### rework LOAD_GLOBAL arguments when functions are loaded and add the function address to the GLOBALS_MEM_CONTENT ##### functions addresses are the highest addresses in the GLOBAL_MEM,GLOBAL_FUNCTION_ADRESSES_START is used in the core ##### to decide wheter it is a normal LOAD_GLOBAL or if the LOAD global loads a function for basefuncname,callfunctionname,index in list_Load_global_when_fcall: if not occuring_globals_dict.has_key(callfunctionname): occuring_globals_dict[callfunctionname]=globals_addr self.GLOBALS_MEM_CONTENT.append(Processed_functions_dict[callfunctionname][0]) ### add the offset address of the function, to the GLOBAL memory globals_addr=globals_addr+1 programm_dict[basefuncname][1][index]=occuring_globals_dict[callfunctionname] #currentprogramm_arg[index]=occuring_globals_dict[func_name] #### stitch programms of the induvidual functions together self.COMPLETE_PROGRAMM_OPCODES=[] self.COMPLETE_PROGRAMM_ARGS=[] for FuncName in function_names_inorder: self.COMPLETE_PROGRAMM_OPCODES.extend(programm_dict[FuncName][0]) self.COMPLETE_PROGRAMM_ARGS.extend(programm_dict[FuncName][1]) self.GLOBAL_STACK_SIZE=0 for offset,func_object in Processed_functions_dict.itervalues(): self.GLOBAL_STACK_SIZE=max(func_object.func_code.co_stacksize,self.GLOBAL_STACK_SIZE) ## myhdl only works with tuples self.GLOBAL_STACK_SIZE=self.GLOBAL_STACK_SIZE if len(self.GLOBALS_MEM_CONTENT)==0: self.GLOBALS_MEM_CONTENT=(0,) #needs to be a tuple of integers else: self.GLOBALS_MEM_CONTENT=tuple(self.GLOBALS_MEM_CONTENT) self.CONSTANTS_MEM_CONTENT=tuple(self.CONSTANTS_MEM_CONTENT) self.COMPLETE_PROGRAMM_OPCODES=tuple(self.COMPLETE_PROGRAMM_OPCODES) self.COMPLETE_PROGRAMM_ARGS=tuple(self.COMPLETE_PROGRAMM_ARGS) self.GLOBAL_OPCODE_ARG_MAX_VALUE=max(self.COMPLETE_PROGRAMM_ARGS) #####end class MakeProzesserByteCode ##################### |