changelog shortlog graph tags branches changeset files file revisions raw help

Mercurial > org > blog / annotate draft/a-bit-of-risc.org

changeset 28: 6d54ccb29de4
parent: db5ece2206cf
author: Richard Westhaver <ellis@rwest.io>
date: Sun, 18 Aug 2024 22:16:12 -0400
permissions: -rw-r--r--
description: weekend warrior
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
1
 #+title: A Bit of RISC
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
2
 #+date: [2024-03-11 Mon]
21
1204cefcfd28 style updates
Richard Westhaver <ellis@rwest.io>
parents: 20
diff changeset
3
 #+setupfile: ../../clean.theme
28
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
4
 #+property: header-args :eval no-export
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
5
 I recently picked up [[https://dl.acm.org/doi/10.5555/2462741][Hacker's Delight]] and having a lot of fun with
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
6
 it. It's a collection of bit-manipulation tricks collected by hackers
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
7
 over many years. You can flip open pretty much anywhere in the book
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
8
 and start learn something really cool.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
9
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
10
 There's something about seeing bit strings and assembly code in a book
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
11
 that really catches my attention, this one goes a bit further by even
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
12
 describing a complete RISC (Reduced Instruction Set Computer) we can
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
13
 implement to play around with the various tricks.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
14
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
15
 As an exercise and for fun, I'd like to employ some Lisp-fu here and
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
16
 implement a small VM specifically designed for mangling bits.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
17
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
18
 As a fair warning, I'm not a mathematician and I don't write proofs
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
19
 often. If I get something wrong or there is a better way of doing
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
20
 things, let me know!
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
21
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
22
 You can find most of the code from the book [[https://github.com/hcs0/Hackers-Delight][here]].
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
23
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
24
 * Design
28
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
25
 :PROPERTIES:
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
26
 :ID:       c030566f-1ede-4edc-b393-d2c6c1c2d19f
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
27
 :END:
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
28
 ** Data Representation
28
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
29
 :PROPERTIES:
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
30
 :ID:       6d93e084-1047-4a33-adb3-5c90af96ead0
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
31
 :END:
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
32
 We'll be sticking with a 32-bit word length as recommended in the
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
33
 Preface. We will also represent registers as integers whenever
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
34
 possible, instead of say a bit-vector. Without going into too much
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
35
 detail, it's much more efficient to do bitwise ops on integers
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
36
 instead of bit-vectors in Lisp.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
37
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
38
 We need a minimum of 16 general purpose registers, typically of word
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
39
 length, with R0 reserved for a constant 0. To address 16 different
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
40
 registers we actually only need 4 bits - 5-bits if we needed 32, 6 for
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
41
 64, etc.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
42
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
43
 Floating-point support and special purpose registers are not required.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
44
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
45
 ** Instructions
28
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
46
 :PROPERTIES:
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
47
 :ID:       fb86a212-b49a-44ff-b30b-32c789ca55e2
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
48
 :END:
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
49
 The Hacker's Delight RISC architecture is described in two tables,
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
50
 denoted =basic RISC= and =full RISC= respectively.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
51
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
52
 Most instructions take two source registers =RA= and =RB= with a
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
53
 destination register =RT=. The actual general-purpose registers are
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
54
 labelled =R0= (containg the constant 0) through =R15=.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
55
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
56
 A 3-Address machine is assumed and some instructions take 16-bit
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
57
 signed or unsigned immediate values - denoted =I= and =Iu=
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
58
 respectively.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
59
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
60
 #+tblname: Basic Instruction Set (basic RISC)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
61
 | Opcode Mnemonic                                                 | Operands  | Description                                                                                                                             |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
62
 |-----------------------------------------------------------------+-----------+-----------------------------------------------------------------------------------------------------------------------------------------|
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
63
 | add,sub,mul,div,divu,rem,remu                                   | RT,RA,RB  | RT <- (op RA RB)                                                                                                                        |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
64
 | addi,muli                                                       | RT,RA,I   | RT <- (op RA I), I is a 16-bit signed immediate-value                                                                                   |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
65
 | addis                                                           | RT,RA,I   | RT <- (+ RA (\vert\vert I 0x0000))                                                                                                      |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
66
 | and,or,xor                                                      | RT,RA,RB  | RT <- (op RA RB)                                                                                                                        |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
67
 | andi,ori,xori                                                   | RT,RA,Iu  | As above, expect the last operand is a 16-bit unsigned immediate-value                                                                  |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
68
 | beq,bne,blt,ble,bgt,bge                                         | RT,target | Branch to target if (op RT)                                                                                                             |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
69
 | bt,bf                                                           | RT,target | Branch true/false, same as bne/beq resp                                                                                                 |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
70
 | cmpeq,cmpne,cmplt,cmple,cmpgt,cmpge,cmpltu,cmpleu,cmpgtu,cmpgeu | RT,RA,RB  | RT <- (if (op RA RB) 1 0)                                                                                                               |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
71
 | cmpieq,cmpine,cmpilt,cmpile,cmpigt,cmpige                       | RT,RA,I   | Like cmpeq except second comparand is a 16-bit signed immediate-value                                                                   |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
72
 | cmpiequ,cmpineu,cmpiltu,cmpileu,cmpigtu,cmpigeu                 | RT,RA,I   | Like cmpltu except second comparand is a 16-bit unsigned immediate-value                                                                |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
73
 | ldbu,ldh,ldhu,ldw                                               | RT,d(RA)  | Load an unsigned-byte, signed-halfword, unsigned-halfword, or word into RT from (+ RA d) where d is a 16-bit signed immediate-value     |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
74
 | mulhs,mulhu                                                     | RT,RA,RB  | RT gets the high-order 32 bits of (* RA RB)                                                                                             |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
75
 | not                                                             | RT,RA     | RT <- bitwise one's-complement of RA                                                                                                    |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
76
 | shl,shr,shrs                                                    | RT,RA,RB  | RT <- RA shifted left or right by rightmost six bits of RB; 0-fill except for shrs, which is sign-fill (shift amount treated modulo 64) |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
77
 | shli,shri,shrsi                                                 | RT,RA,Iu  | RT <- RA shifted left or right by 5-bit immediate field                                                                                 |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
78
 | stb,sth,stw                                                     | RS,d(RA)  | Store a byte,halfword,word from RS into memory at location (+ RA d) where d is a 16-bit signed immediate-value                          |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
79
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
80
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
81
 #+name: Addition Instructions (full RISC)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
82
 | Opcode Mnemonic                                                 | Operands  | Description                                                                                            |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
83
 |-----------------------------------------------------------------+-----------+--------------------------------------------------------------------------------------------------------|
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
84
 | abs,nabs                                                        | RT,RA     | RT <- (op RA)                                                                                          |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
85
 | andc,eqv,nand,nor,orc                                           | RT,RA,RB  | RT <- (op RA RB)                                                                                       |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
86
 | extr                                                            | RT,RA,I,L | extract bits I through I+L-1 of RA and place them right-adjusted in RT, with 0-fill                    |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
87
 | extrs                                                           | RT,RA,I,L | Like extr, but sign-fill                                                                               |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
88
 | ins                                                             | RT,RA,I,L | Insert bits 0 through L-1 of RA into bits I through I+L-1 of RT                                        |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
89
 | nlz                                                             | RT,RA     | RT gets count of leading 0's in RA (0 to 32)                                                           |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
90
 | pop                                                             | RT,RA     | RT gets the number of 1-bits in RA (0 to 32)                                                           |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
91
 | ldb                                                             | RT,d(RA)  | Load a signed byte into RT from memory at location (+ RA d) where d is a 16-bit signed immediate value |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
92
 | moveq,movne,movlt,movle,movgt,movge                             | RT,RA,RB  | RT <- RA rotate-shifted left or right by the rightmost 5-bits of RB                                    |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
93
 | shlr,shrr                                                       | RT,RA,RB  | RT <- RA rotate-shifted left or right by the rightmost 5-bits of RB                                    |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
94
 | shlri,shrri                                                     | RT,RA,Iu  | RT <- RA rotate-shifted left or right by the 5-bit immediate field                                     |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
95
 | trpeq,trpne,trplt,trple,trpgt,trpge,trpltu,trpleu,trpgtu,trpgeu | RA,RB     | Trap (interrupt) if (op RA RB)                                                                         |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
96
 | trpieq,trpine,trpilt,trpile,trpigt,trpige                       | RA,I      | Trap if (op RA I) where I is a 16-bit signed immediate-value                                           |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
97
 | trpiequ,trpineu,trpiltu,trpileu,trpigtu,trpigeu                 | RA,Iu     | Trap if (op RA Iu) where Iu is a 16-bit unsigned immediate-value                                       |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
98
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
99
 There is also some extensions, which are like macros that usually
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
100
 expand to a single instruction.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
101
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
102
 #+name: Extended Mnemonics
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
103
 | Extended Mnemonic | Expansion        | Description               |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
104
 |-------------------+------------------+---------------------------|
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
105
 | b target          | beq R0,target    | Unconditional branch      |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
106
 | li RT,I           | (addi,addis,ori) | Load immediate            |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
107
 | mov RT,RA         | ori RT,RA,0      | Move register RA to RT    |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
108
 | neg RT,RA         | sub RT,R0,RA     | Negate (two's-complement) |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
109
 | subi RT,RA,I      | addi RT,RA,-I    | Subtract immediate        |
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
110
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
111
 All of these instructions are available on x86,arm,riscv and the likes
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
112
 so no real surprises. We will implement the basic set in Lisp, mapping
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
113
 instructions directly to Lisp functions using macros.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
114
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
115
 ** Execution Model
28
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
116
 :PROPERTIES:
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
117
 :ID:       f84fcd3d-86ad-4b9b-a330-4572d6120559
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
118
 :END:
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
119
 We'll build this machine in Lisp and use plenty intrinsics from
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
120
 SBCL. As a starting point I followed Paul Khuong's excellent blog
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
121
 post: [[https://pvk.ca/Blog/2014/03/15/sbcl-the-ultimate-assembly-code-breadboard/][SBCL: The ultimate assembly code breadboard]].
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
122
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
123
 Some things to keep in mind for our machine:
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
124
 - every instruction requires at most two register reads and one
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
125
   register write - good for compilers
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
126
 - every instruction counts as a single cycle
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
127
 - we pay no attention to instruction-level parallelism
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
128
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
129
 * The HAKMEM VM
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
130
 :properties:
27
db5ece2206cf meta and task updates
Richard Westhaver <ellis@rwest.io>
parents: 25
diff changeset
131
 :header-args: :session t :results none :noeval t
28
6d54ccb29de4 weekend warrior
Richard Westhaver <ellis@rwest.io>
parents: 27
diff changeset
132
 :ID:       43484c58-ab29-481c-b2b9-17ab4d91e22f
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
133
 :end:
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
134
 #+name: defpackage
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
135
 #+begin_src lisp
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
136
   (ql:quickload :prelude)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
137
   (in-package :std-user)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
138
   (defpackage :hakmem
23
Richard Westhaver <ellis@rwest.io>
parents: 21
diff changeset
139
     (:use :cl :std :std-user)
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
140
     (:import-from :sb-assem :inst)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
141
     (:import-from :sb-vm :immediate-constant :registers :zero :ea))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
142
   (in-package :hakmem)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
143
   ;; (in-package :sb-x86-64-asm)
24
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
144
   ;; (in-readtable :std)
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
145
   (declaim (optimize (speed 3) (safety 1)))
25
f23bffbe2f4c updates
Richard Westhaver <ellis@rwest.io>
parents: 24
diff changeset
146
 
f23bffbe2f4c updates
Richard Westhaver <ellis@rwest.io>
parents: 24
diff changeset
147
   (eval-always
f23bffbe2f4c updates
Richard Westhaver <ellis@rwest.io>
parents: 24
diff changeset
148
     (defconstant +word-size+ 32 "default word size and register length."))
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
149
 #+end_src
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
150
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
151
 #+name: vars
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
152
 #+begin_src lisp :package hakmem
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
153
   (declaim (type (unsigned-byte #.+word-size+) +ro+))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
154
   (defconstant +r0+ 0 "constant value for register 0")
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
155
   (defvar *stack* (make-array 8 :initial-contents (list sb-vm::r8-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
156
                                                         sb-vm::r9-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
157
                                                         sb-vm::r10-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
158
                                                         sb-vm::r11-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
159
                                                         sb-vm::r12-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
160
                                                         sb-vm::r13-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
161
                                                         sb-vm::r14-tn
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
162
                                                         sb-vm::r15-tn)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
163
   (defvar *stack-pointer*)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
164
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
165
   (defvar *rax* sb-vm::rax-tn)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
166
   (defvar *rbx* sb-vm::rax-tn)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
167
   (defvar *rcx* sb-vm::rax-tn)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
168
   (defvar *rdx* sb-vm::rax-tn)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
169
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
170
   ;; (@ 0) returns the (current) register for TOS, (@ 1) returns
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
171
   ;; the one just below, etc.
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
172
   (defun @ (i)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
173
     (aref *stack* (mod (+ i *stack-pointer*) (length *stack*))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
174
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
175
   (defvar *code-base* sb-vm::rsi-tn)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
176
   (defvar *virtual-ip* sb-vm::rdi-tn)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
177
   (sb-x86-64-asm::get-gpr :qword 4)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
178
   ;; (sb-vm::immediate-constant-sc 10000)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
179
   ;; arena vector or list?
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
180
   (defvar *instructions* (make-hash-table :test #'equal))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
181
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
182
   (defvar *primitive-code-offset* (* 64 67))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
183
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
184
   (defstruct code-page
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
185
     (alloc 0) ;; next free byte
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
186
     (code (make-array *primitive-code-offset* :element-type 'octet)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
187
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
188
   (defun emit-code (pages emitter)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
189
     ;; there must be as many code pages as there are stack slots
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
190
     (assert (= (length *stack*) (length pages)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
191
     ;; find the rightmost starting point, and align to 16 bytes
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
192
     (let* ((alloc (logandc2 (+ 15 (reduce #'max pages :key #'code-page-alloc))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
193
                             15))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
194
            (bytes (loop for i below (length pages)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
195
                         for page = (elt pages i)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
196
                         collect (let ((segment (sb-assem:make-segment))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
197
                                       (*stack-pointer* i))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
198
                                   ;; assemble the variant for this value
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
199
                                   ;; of *stack-pointer* in a fresh code
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
200
                                   ;; segment
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
201
                                   (sb-assem:assemble (segment)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
202
                                     ;; but first, insert padding
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
203
                                     (sb-vm::emit-long-nop segment (- alloc (code-page-alloc page)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
204
                                     (funcall emitter))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
205
                                   ;; tidy up any backreference
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
206
                                   (sb-assem:finalize-segment segment)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
207
                                   ;; then get the (position-independent) machine
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
208
                                   ;; code as a vector of bytes
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
209
                                   (sb-assem:segment-contents-as-vector segment)))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
210
       ;; finally, copy each machine code sequence to the right code page
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
211
       (map nil (lambda (page bytes)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
212
                  (let ((alloc (code-page-alloc page)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
213
                    (replace (code-page-code page) bytes :start1 alloc)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
214
                    (assert (<= (+ alloc (length bytes)) (length (code-page-code page))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
215
                    (setf (code-page-alloc page) (+ alloc (length bytes)))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
216
            pages bytes)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
217
       ;; and return the offset for that code sequence
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
218
       alloc))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
219
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
220
   (defun emit-all-code (&rest emitters)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
221
     (let ((pages (loop repeat (length *stack*)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
222
                        for page = (make-code-page)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
223
                        ;; prefill everything with one-byte NOPs
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
224
                        do (fill (code-page-code page) #x90)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
225
                        collect page)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
226
       (values (mapcar (lambda (emitter)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
227
                         (emit-code pages emitter))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
228
                       emitters)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
229
               pages)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
230
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
231
   (defun next (&optional offset)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
232
     (setf offset (or offset 0)) ; accommodate primops that frob IP
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
233
     (let ((rotation (mod *stack-pointer* (length *stack*))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
234
       (inst movzx *rax* (make-ea :dword :base *virtual-ip*
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
235
                                         :disp offset))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
236
       (unless (= -4 offset)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
237
         (inst add *virtual-ip* (+ 4 offset)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
238
       (if (zerop rotation)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
239
           (inst add *rax* *code-base*)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
240
           (inst lea *rax* (make-ea :qword :base *code-base*
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
241
                                           :index *rax*
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
242
                                           :disp (* rotation *primitive-code-offset*))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
243
       (inst jmp *rax*)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
244
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
245
   (defun swap ()
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
246
     (inst xchg (@ 0) (@ 1)) ; exchange top of stack and stack[1]
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
247
     (next))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
248
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
249
 #+end_src
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
250
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
251
 #+name: instructions
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
252
 #+begin_src lisp :package hakmem
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
253
   ;; todo
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
254
   (defun %parse-reg3 (rt ra rb))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
255
   (defun %parse-reg2i (rt ra i))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
256
   (defun %parse-reg2ui (rt ra ui))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
257
   (defmacro def-inst (name args &body body)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
258
       ;; todo: compose a function based on regs+args+body
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
259
       `(let ((sc *scratch*)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
260
              (r0 +r0+)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
261
              (ra 0)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
262
              (rb 0)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
263
              (rt 0))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
264
          (declare (ignorable sc r0 ra rb rt))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
265
          (setf (gethash ',name *instructions*) (lambda ,args (progn ,@body)))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
266
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
267
   (defmacro def-prim (name op)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
268
     `(def-inst ,name () (setf rt (,op ra rb))))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
269
 #+end_src
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
270
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
271
 #+name: prims
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
272
 #+begin_src lisp :package hakmem
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
273
   (def-prim add +)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
274
   (def-prim sub -)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
275
   (def-prim mul *)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
276
   (def-prim div /)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
277
   ;; divu
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
278
   (def-prim rem mod)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
279
   ;; remu
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
280
   (def-prim cmpeq =)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
281
   (def-prim cmpne /=)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
282
   (def-prim cmplt <)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
283
   (def-prim cmple <=)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
284
   (def-prim cmpgt >)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
285
   (def-prim cmpge >=)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
286
   ;; ltu leu gtu geu
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
287
   (def-inst addi (i)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
288
     (setf rt (+ ra i)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
289
   (def-inst muli (i)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
290
     (setf rt (* ra i)))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
291
   (def-prim and logand)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
292
   (def-prim or logior)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
293
   (def-prim xor logxor)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
294
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
295
   (defun get-inst (i) (gethash i *instructions*))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
296
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
297
   (defmacro %inst (i &body args)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
298
     `(funcall (get-inst ',i) ,@args))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
299
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
300
   (defun list-instructions (&optional (tbl *instructions*))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
301
     (hash-table-alist tbl))
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
302
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
303
 #+end_src
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
304
 #+name: instruction-list
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
305
 #+begin_src lisp :results replace :exports both :package hakmem
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
306
   (list-instructions)
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
307
 #+end_src
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
308
 
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
309
 #+RESULTS: instruction-list
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
310
 #+begin_example
24
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
311
 ((XOR . #<FUNCTION (LAMBDA ()) {101CF0367B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
312
  (OR . #<FUNCTION (LAMBDA ()) {101CF036AB}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
313
  (AND . #<FUNCTION (LAMBDA ()) {101CF036DB}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
314
  (MULI . #<FUNCTION (LAMBDA (I)) {101CF0370B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
315
  (ADDI . #<FUNCTION (LAMBDA (I)) {101CF0373B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
316
  (CMPGE . #<FUNCTION (LAMBDA ()) {101CF0376B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
317
  (CMPGT . #<FUNCTION (LAMBDA ()) {101CF0379B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
318
  (CMPLE . #<FUNCTION (LAMBDA ()) {101CF037CB}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
319
  (CMPLT . #<FUNCTION (LAMBDA ()) {101CF037FB}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
320
  (CMPNE . #<FUNCTION (LAMBDA ()) {101CF0382B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
321
  (CMPEQ . #<FUNCTION (LAMBDA ()) {101CF0385B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
322
  (REM . #<FUNCTION (LAMBDA ()) {101CF0388B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
323
  (DIV . #<FUNCTION (LAMBDA ()) {101CF038DB}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
324
  (MUL . #<FUNCTION (LAMBDA ()) {101CF0391B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
325
  (SUB . #<FUNCTION (LAMBDA ()) {101CF0394B}>)
Richard Westhaver <ellis@rwest.io>
parents: 23
diff changeset
326
  (ADD . #<FUNCTION (LAMBDA ()) {101CF0397B}>))
18
Richard Westhaver <ellis@rwest.io>
parents:
diff changeset
327
 #+end_example