copyleft: gplv3 added and set repo to public
[calu.git] / progs / deepjit.s
1 ;    `Deep Thought', a softcore CPU implemented on a FPGA
2 ;
3 ;   Copyright (C) 2010 Markus Hofstaetter <markus.manrow@gmx.at>
4 ;   Copyright (C) 2010 Martin Perner <e0725782@student.tuwien.ac.at>
5 ;   Copyright (C) 2010 Stefan Rebernig <stefan.rebernig@gmail.com>
6 ;   Copyright (C) 2010 Manfred Schwarz <e0725898@student.tuwien.ac.at>
7 ;   Copyright (C) 2010 Bernhard Urban <lewurm@gmail.com>
8 ;
9 ;   This program is free software: you can redistribute it and/or modify
10 ;   it under the terms of the GNU General Public License as published by
11 ;   the Free Software Foundation, either version 3 of the License, or
12 ;   (at your option) any later version.
13 ;
14 ;   This program is distributed in the hope that it will be useful,
15 ;   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;   GNU General Public License for more details.
18 ;
19 ;   You should have received a copy of the GNU General Public License
20 ;   along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
22 #define PROGINSTR stw r0, PDATA(r13)
23 #include "dt_inc.s"
24 .data
25 .org 0x10
26 inputdata:
27 ;8 * 8 4
28 .fill 1, 0x382A3834
29 ;1 X * 8
30 .fill 1, 0x31582A38
31 ;+ D X -
32 .fill 1, 0x2B44582D
33 ;P \xF8 J D
34 .fill 1, 0x50F84A44
35 ;+ * 8 6
36 .fill 1, 0x2B2A3836
37 ;\000 \020 I D
38 .fill 1, 0x00204944
39 ;~ < \000 \000
40 .fill 1, 0x7E3C0000
41 ;8 P \005 J
42 .fill 1, 0x3850054A
43 ;* 8
44 .fill 1, 0x2A38
45
46 ;needed for jumps
47 ;assuming that no more than 42 instr are used
48 instrtable:
49 .fill 42, 0
50
51 prog_eof:
52 .ifill pop r7
53 .ifill ret+
54
55 prog_mul:
56 .ifill pop r7
57 .ifill ldis r8, 0;0xed400004
58 .ifill mov r0, r7;0xe1038000
59 .ifill andx r0, 1;0xe2800008
60 .ifill adddnz r8, r8, r6;0x00443001
61 .ifill subinz r7, r7, 1;0x01bb8008
62 .ifill addizs r7, r7, 0;0x113b8000
63 ;loop:
64 .ifill adddnz r8, r8, r6;0x00443001
65 .ifill adddnz r8, r8, r6;0x00443001
66 .ifill subi r7, r7, 2;0xe1bb8010
67 .fill 0x0b7ffe83;brnz+ loop
68 .ifill mov r6, r8
69
70 prog_consts:
71 .ifill push r6
72 .fill 0xed300004;ldis r6, CONST
73
74 prog_add:
75 .ifill pop r7
76 .ifill add r6, r7, r6;0xe03bb000
77
78 prog_sub:
79 .ifill pop r7
80 .ifill sub r7, r7, r6;0xe0bbb000
81 .ifill mov r6, r7
82
83 prog_lessthan:
84 .ifill pop r7
85 .ifill cmp r7, r6;0xec3b0000
86 .ifill movdlt r6, r14
87 .ifill movge r6, r15
88
89 prog_dup:
90 .ifill push r6
91
92 prog_jmp:
93 .ifill cmpi r6,0;0xecb00000
94 .ifill pop r6
95 ;static calced
96 .fill 1, 0x0b000003;brne+ CONST
97
98 prog_imm:
99 .ifill push r6
100 .fill 1, 0xed300000;ldil r6, CONST
101 .fill 1, 0xed300002;ldih r6, CONST
102
103 prog_pop:
104 .ifill pop r6
105
106 prog_xch:
107 .ifill pop r7
108 .ifill push r6
109 .ifill mov r6, r7
110
111 prog_not:
112 .ifill not r6;0xe4b7fffa
113
114 .text
115 .org 0
116 start:
117         call+ main
118         call+ main
119         ret
120
121
122 main:
123
124         call+ u_init
125         call+ u_recv_byte
126
127         ; benchprolog
128         call t_init
129         call t_stop
130         ldis r1, 0
131         call t_valset
132         call t_start
133         ; /benchprolog
134
135         ;set address of input
136         ldis r1, inputdata@lo
137         ldih r1, inputdata@hi
138
139         ;set address of program start
140         ldis r2, (prog_start/4)@lo
141         ldih r2, (prog_start/4)@hi
142
143         ;set address to instruction table
144         ldis r3, instrtable@lo
145         ldih r3, instrtable@hi
146
147         ;set address to defer table
148         ldis r9, defertable@lo
149         ldih r9, defertable@hi
150
151         ldis r13, PBASE@lo
152         ldih r13, PBASE@hi
153
154         ;set programmer address
155         stw r2, PADDR(r13)
156
157         ;call jit compiler
158         call+ jit
159
160         ;set address to stack
161         ;ldil r3, stack@lo
162         ;ldih r3, stack@hi
163
164         ;make r15 a 0-register
165         ldis r15, 0
166         ;make r14 a 8-bit -1-register
167         ldis r14, 0xFF
168
169         ;call jit'ed prog
170         call+ prog_start
171
172         ; benchepilog
173         push r6
174         call+ t_init
175         call+ t_stop
176         call+ t_valget
177         subi r0, r0, 0xc ; offset abziehen
178         pop r3
179         push r0
180         push r3
181         ; /benchepilog
182
183         ;send result
184         call+ u_init
185         pop r1
186         call u_send_byte
187         call u_send_newline
188         pop r1
189         call u_send_uint
190         call u_send_newline
191
192         br+ main
193
194 ;first version only supports backward jumps
195 jit:
196         ;r1 ... address to input, every byte is a new input
197         ;       includes pc implicitly
198         ;r2 ... address to program start
199         ;r3 ... address of instruction table
200         ;r4 ... gets loaded with instr. prog. addr.
201         ;r5 ... input
202         ;r9 ... address to actual entry in defer table
203         ;r10... address to defer table
204         ;r13 .. programmer address
205
206         ;load address of program
207         ldil r14, prog_mul@lo
208         ldih r14, prog_mul@hi
209
210         ldil r15, prog_consts@lo
211         ldih r15, prog_consts@hi
212
213         ;backup defer table address
214         mov r10, r9
215         br+ vm_loop_1
216
217 vm_default:     
218 vm_loop:
219         ;increment input address
220         addi r1, r1, 1
221 vm_loop_1:
222         ;store address of next instruction in table
223         stw r2, 0(r3)
224         ;increment instr. table
225         addi r3, r3, 4
226
227         ;load input
228         ldb r5, 0(r1)
229         ;we need to multiply input by 4 to get correct address offset
230         lls r0, r5, 2
231         ;calc position in jumptable
232         ldw r0, jumptable(r0)
233         ;jump to instr
234         brr r0
235
236 vm_eof:
237         ;load address of program
238         ldil r4, prog_eof@lo
239         ldih r4, prog_eof@hi
240         ;program instruction (2)
241         ldw r0, 0(r4)
242         stw r0, PDATA(r13)
243         ldw r0, 4(r4)
244         stw r0, PDATA(r13)
245
246         ;end of program
247         ;now it is time to clear up the defer table
248
249         ldil r7, prog_jmp@lo
250         ldih r7, prog_jmp@hi
251         ;load branch template
252         ldw r7, 8(r7)
253
254         ;if actual and base are equal, no entry
255         cmp r9, r10
256         ;return
257         reteq-
258
259 vm_defer:
260         ;load pointer to where to jump to
261         ldw r6, 0(r10)
262         ;load where to jump to
263         ldw r6, 0(r6)
264         ;load where to save from defer table
265         stw r8, 4(r10)
266
267         ;generate branch
268         sub r11, r6, r8
269         ;lrs r11, r11, 2
270         ;set the upper 16 bit 0
271         andx r11, 0xFFFF
272         ;shift to the position of imm in br
273         lls r11, r11, 7
274         or r6, r7, r11
275         
276         stw r8, PADDR(r13)      
277         stw r6, PDATA(r13)
278
279         addi r10, r10, 8
280         cmp r10, r9
281         reteq+
282         br+ vm_defer
283
284 ;case *
285 ;42
286 vm_mul:
287         ;program instruction (14)
288         ldw r0, 0(r14)
289         PROGINSTR
290         ldw r0, 4(r14)
291         PROGINSTR
292         ldw r0, 8(r14)
293         PROGINSTR
294         ldw r0, 12(r14)
295         PROGINSTR
296         ldw r0, 16(r14)
297         PROGINSTR
298         ldw r0, 20(r14)
299         PROGINSTR
300         ldw r0, 24(r14)
301         PROGINSTR
302         ldw r0, 28(r14)
303         PROGINSTR
304         ldw r0, 32(r14)
305         PROGINSTR
306         ldw r0, 36(r14)
307         PROGINSTR
308         ldw r0, 40(r14)
309         PROGINSTR
310         ldw r0, 44(r14)
311         PROGINSTR
312
313         ;increment address
314         addi r2, r2, 12
315
316         br+ vm_loop
317
318 ;case +
319 ;43
320 vm_add:
321         ;load address of program
322         ldil r4, prog_add@lo
323         ldih r4, prog_add@hi
324
325         ;program instruction (5)
326         ldw r0, 0(r4)
327         PROGINSTR
328         ldw r0, 4(r4)
329         PROGINSTR
330
331         ;increment address
332         addi r2, r2, 2
333
334         br+ vm_loop
335
336 ;case -
337 ;45
338 vm_sub:
339         ;load address of program
340         ldil r4, prog_sub@lo
341         ldih r4, prog_sub@hi
342
343         ;program instruction (5)
344         ldw r0, 0(r4)
345         PROGINSTR
346         ldw r0, 4(r4)
347         PROGINSTR
348         ldw r0, 8(r4)
349         PROGINSTR
350
351         ;increment address
352         addi r2, r2, 3
353
354         br+ vm_loop
355
356 ;case 0 1 2 3 4 5 6 7 8 9
357 ;48-57
358 vm_consts:
359         ;program instruction (3)
360         ldw r0, 0(r15)
361         PROGINSTR
362         ldw r0, 4(r15)
363         ;the first instr. loads r6 with the number
364         ;thus we shall emulate this
365
366         ;call number
367         subi r6, r5, 48
368         ;shift 3 bits left, as the immediate in ldi has
369         ;an offset of 3
370         lls r6, r6, 3
371         ;now 'add' this to the ldi
372         or r0, r0, r6
373
374         ;store this 'dynamic' instruction
375         PROGINSTR
376
377         ;increment address
378         addi r2, r2, 2
379
380         br+ vm_loop
381
382 ;case <
383 ;60
384 vm_lessthan:
385         ;load address of program
386         ldil r4, prog_lessthan@lo
387         ldih r4, prog_lessthan@hi
388
389         ;program instruction (6)
390         ldw r0, 0(r4)
391         PROGINSTR
392         ldw r0, 4(r4)
393         PROGINSTR
394         ldw r0, 8(r4)
395         PROGINSTR
396         ldw r0, 12(r4)
397         PROGINSTR
398
399         ;increment address
400         addi r2, r2, 4
401
402         br+ vm_loop
403
404 ;case D
405 ;68
406 vm_dup:
407         ldil r4, prog_dup@lo
408         ldih r4, prog_dup@hi
409
410         ;program instruction (3)
411         ldw r0, 0(r4)
412         PROGINSTR
413
414         ;increment address
415         addi r2, r2, 1
416
417         br+ vm_loop
418
419 ;case I
420 ;73
421 vm_imm:
422         ;the following instructions calculate the immediate
423         ;load new high byte
424         ldb r6, 4(r1)
425         ;shift high byte
426         lls r6, r6, 8
427         ;load 2nd byte
428         ldb r7, 3(r1)
429         ;add to high byte
430         add r6, r6, r7
431         ;shift
432         lls r6, r6, 8
433         ;load
434         ldb r7, 2(r1)
435         ;add
436         add r6, r6, r7
437         ;shift
438         lls r6, r6, 8
439         ;load
440         ldb r7, 1(r1)
441         ;add
442         add r6, r6, r7
443
444         ;now we will generate ldih/l which will store this
445         ;immediate into a register
446
447         ;load address of program
448         ldil r4, prog_imm@lo
449         ldih r4, prog_imm@hi
450
451         ldw r0, 0(r4)
452         PROGINSTR
453
454         ;save r6 to r7
455         mov r7, r6
456
457         ;generate 1st instr
458         ldw r0, 4(r4)
459         andx r6, 0xFFFF
460         lls r6, r6, 3
461         or r0, r0, r6
462         PROGINSTR
463
464         ;generate 2nd instr
465         ldw r0, 8(r4)
466         andxh r7, 0xFFFF
467         lrs r7, r7, 13
468         or r0, r0, r7
469         PROGINSTR
470
471         ;increment address
472         addi r2, r2, 3
473
474         ;pc+4
475         addi r1, r1, 4
476         br+ vm_loop
477
478 ;case J
479 ;74
480 vm_jmp:
481         ;gfreit mi net ...
482         ;gespeicherte instrs sollten input indepentent sein
483         ;jumptable verwenden
484         ;fuer forward jumps muss deferrer table gemacht werden *puke*
485
486         ;load address of program
487         ldil r4, prog_jmp@lo
488         ldih r4, prog_jmp@hi
489
490         ;compare to 0
491         ;cmpi r6,0
492         ldw r0, 0(r4)
493         PROGINSTR
494
495         ;program instruction (2)
496         ;pop r6
497         ldw r0, 4(r4)
498         PROGINSTR
499
500         ;we add the offset to this instruction
501         addi r8, r2, 2
502
503
504         ;we know calculate the jump destination
505         ;set r6 to 0 (to clear upper bytes)
506         ldis r6, 0
507         ;load pc+1 input
508         ldb r6, 1(r1)
509         ;compare input with neg. max of 8 bit
510         cmpi r6, 0x80
511         brlt- vm_possign
512
513
514
515         ;generate negativ offset
516         ldis r7, 0xFF00
517         ;r6 is now the 'real' negativ number
518         or r6, r6, r7
519         ;todo: testing showed (at least once) we are off by 2 instr.
520         ;addi r6, r6, 2
521         ;multiply by to get the offset
522         lls r6, r6, 2
523         ;generate address in table
524         add r6, r3, r6
525         ;r0 now has the target address
526         ;todo: 0-4?
527         ldw r0, 0(r6)
528         ;we calc the offset
529         sub r8, r0, r8
530         ;we shift 2 bits out, because rel. br takes instr.
531         ;count and not address amount ...
532         ;lrs r8, r8, 2
533         ;set the upper 16 bit 0
534         andx r8, 0xFFFF
535         ;shift to the position of imm in br
536         lls r8, r8, 7
537         ;load template br
538         ldw r0, 8(r4)
539         or r0, r0, r8
540         PROGINSTR
541
542         ;increment address
543         addi r2, r2, 3
544
545         br+ vm_loop
546
547
548 vm_possign:
549         ;we know save the address in the instrtable where the addr to jump to stands
550         ;the value doesn't exists at the moment, but it will at evaluation
551
552         ;save position to save the instr into defer table
553         stw r8, 4(r9)
554
555         ;we need one instruction to have the correct offset (?)
556         PROGINSTR
557
558         ;todo: check if -1 is needed
559         ;subi r6, r6, 1
560         ;multiply with 2 to get offset right
561         lls r6, r6, 2
562         ;add to current base
563         add r6, r3, r6
564         ;save the address to defer table
565         stw r6, 0(r9)
566         ;increment defer table address
567         addi r9, r9, 8
568         ;increment address
569         addi r2, r2, 3
570         br+ vm_loop
571
572 ;case P
573 ;80
574 vm_pop:
575         ;load address of program
576         ldil r4, prog_pop@lo
577         ldih r4, prog_pop@hi
578
579         ;program instruction (1)
580         ldw r0, 0(r4)
581         PROGINSTR
582
583         ;increment address
584         addi r2, r2, 1
585
586         br+ vm_loop
587
588 ;case X
589 ;88
590 vm_xch:
591         ;load address of program
592         ldil r4, prog_xch@lo
593         ldih r4, prog_xch@hi
594
595         ;program instruction (4)
596         ldw r0, 0(r4)
597         PROGINSTR
598         ldw r0, 4(r4)
599         PROGINSTR
600         ldw r0, 8(r4)
601         PROGINSTR
602
603         ;increment address
604         addi r2, r2, 3
605
606         br+ vm_loop
607
608 ;case ~
609 ;126
610 vm_not:
611         ;load address of program
612         ldil r4, prog_not@lo
613         ldih r4, prog_not@hi
614
615         ;program instruction (3)
616         ldw r0, 0(r4)
617         PROGINSTR
618
619         ;increment address
620         addi r2, r2, 1
621
622         br+ vm_loop
623
624
625 .data
626 jumptable:
627 ;0
628 .fill 1, vm_eof/4
629 .fill 41, vm_default/4
630 ;42
631 .fill 1, vm_mul/4
632 ;43
633 .fill 1, vm_add/4
634 ;44
635 .fill 1, vm_default/4
636 ;45
637 .fill 1, vm_sub/4
638 ;46-47
639 .fill 2, vm_default/4
640 ;48-57
641 .fill 10, vm_consts/4
642 ;58-59
643 .fill 2, vm_default/4
644 ;60
645 .fill 1, vm_lessthan/4
646 ;61-67
647 .fill 7, vm_default/4
648 ;68
649 .fill 1, vm_dup/4
650 ;69-72
651 .fill 4, vm_default/4
652 ;73
653 .fill 1, vm_imm/4
654 ;74
655 .fill 1, vm_jmp/4
656 ;75-79
657 .fill 5, vm_default/4
658 ;80
659 .fill 1, vm_pop/4
660 ;81-87
661 .fill 7, vm_default/4
662 ;88
663 .fill 1, vm_xch/4
664 ;89-125
665 .fill 37, vm_default/4
666 ;126
667 .fill 1, vm_not/4
668 ;127-255
669 .fill 129, vm_default/4
670
671 ;we assume not more than 3 entries
672 defertable:
673 .fill 6, 0