Why is it called car, cdr, cons?
Ancient history, I believe they are the original assembly command names for ‘contents address register’, ‘contents data register’. Forgotten about cons
Cons is short for ‘constructs’
Sorry cdr is ’contents decrement register, more here https://en.wikipedia.org/wiki/CAR_and_CDR and here https://en.wikipedia.org/wiki/Cons
I could have that slightly wrong but that is the basic idea. Tradition from the old days.
Thanks, interesting read.
No problem
Why doesn’t (cons (cons 1 2) (cons 3 4))
=>
'((1 . 2) . (3 . 4))
`?
Ok, I’ll try to explain but I’m a beginner and I might baffle myself.
The situation here I think is the difference between a list and a pair.
A list has an empty list in the last cdr position of the cons cell chain
(cons 1 ’()) produces a list ’(1)
A pair has does not have an empty list in the cdr position of the cons cell chain
(cons 1 2) produces ’(1 . 2)
@kennethdevel ’((1 . 2) . (3 . 4)) is produced. The default printer just prints it as ’((1 . 2) 3 . 4)
So what you have done is cons’ed a pair which is displayed as (1 . 2) with another pair, creating a pair with the pair (1 . 2) in the car position and (3 . 4) in the cdr position
@soegaard2 Is there a reason why it is printed like that?
as @soegaard2 has just explained the printer displays a pair as (3 . 4) so ’((1 .2) 3 . 4) is the pair in the car position displayed as a separate pair and the second pair displayed as a normal pair within the outer parentheses
Because ’((1 . 2) (3 . 4)) would not be a pair but a list of two pairs
That’s what mwarren explains. A normal list (1 2 3) is short for (1 . (2 . (3 . ()))) so if the cdr is a pair (here the cdr is (2 . (3 . ())) then the printer will print the value as a list.
Yup
@kennethdevel If you are using DrRacket, try turning on “Constructor Printing”
In the menu “Language” choose “Choose Language…”
The click the button “Show Details”
Then choose “Constructor” under “Output style”
Then try your example again.
Then I get (cons (cons 1 2) (cons 3 4))
Yes, that shows you how the cons chain was constructed.
I think it is just the printing that confuses me
when the 3 . 4 is without ()
since (pair? ’((1 . 2) . (3 . 4))) => true
It’s to do with the differences between how the reader works and how the writer works. It is difficult to explain but (pair? ’((1 . 2) 3 . 4)) is also true
The writer shows the result of (cons (cons 1 2) (cons 3 4))` as ’((1 . 2) 3 . 4) as it is the standard way of displaying it but there are a number of possible ways of displaying it. The writer just uses one particular way of doing it.
By default the writer displays cons chains as lists, so that it’s easier to read and reason about them as list. So it never displays the cdr between parentheses.
It just considers the cdr to be “the following part of the list”
so anytime you pass a list or a pair to the cdr part of cons
: (cons x <here>)
it will be considered as the tail of the list, and won’t be displayed as a pair, but will be recursively read until hitting '()
so that when you write (cons 1 (cons 2 (cons 3 '())))
it displays as '(1 2 3)
so in your example, when you write (cons (cons 1 2) (cons 3 4))
you are telling “make me a list that starts with (cons 1 2)
then follows with 3
then finishes with 4
”
which is equivalent to ((1 . 2) 3 . 4)
which is an incomplete list, because it lacks the final '()
@jerome.martin.dev What do you want to run with your 6800 emulator?
@soegaard2 I’m building my own computer from a 6800, but I didn’t want to fry the chip when experimenting, so I made an emulator :stuck_out_tongue:
That sounds as a fun project!
yep :slightly_smiling_face:
Then when building the emulator, I realized that as I was building something that would permit anyone to specify a custom machine architecture, I was making some kind of “universal emulator”, so the emulator project grew a bit bigger than expected :stuck_out_tongue:
I’m focusing on making my own architecture work for now, but I’m planning to add already existing machines
@jerome.martin.dev I see, thanks.
Why is there a distinction betweens pair and list?
I made a DSL to write the MPU part, and a DSL to write the Machine Architecture part. (plus an ASM reader)
@kennethdevel a pair is an incomplete list that does not finish with a '()
therefore you cannot move recursively through a pair
is that good or bad?
it’s good for saving data that you know are not going to be something else than pairs, like key-value pairs in a hashtable for example
Think of pairs as the building blocks of lists. However pairs can be used to build trees as well.
Lists are used so often that they get special treatment.
For example they print nicely.
I know the problem (of projects growing in scope).
I have a 6502 emulator working - and intended to use it for an NES emulator, but never finished.
yeah x)
It can show the title screen of Donkey Kong - so something is working :slightly_smiling_face:
nice!
I also have a lot of racket projects running in parallel… There’s so much to do… A website framework, a container manager, and a game engine…
Plus blog articles I write everytime I learn something new in racket
In the end, nothing gets done :stuck_out_tongue:
!
If only that could be my daily job…
@kennethdevel Although it’s for lisp this page might help explain. Just replace nil with ’() for Racket https://cs.gmu.edu/~sean/lisp/cons/
@jerome.martin.dev btw - why a 6802 ?
that’s what I had on my shelf
as good as any reason
yep :stuck_out_tongue:
@soegaard2 How does the (affects)
work? It seems to be only a literal
see line 585
err - I better read some more
I don’t think I am using the information anywhere.
yeah x)
I guess I saw the opcode tables and thought it could be useful later.
yeah cause I struggled a bit with setting the flags (it might have been the hardest part of making the ALU I think), so I thought you had a cleaner way of doing it than case by case on each op
I made some common utility functions though, like (addition!)
to set the flags for all additions
Sharing between opcodes is a good thing - it is pointless to fix a bug in one place, and forget to fix similar bugs in other instructions.
yeah
one thing I like in my design is that I made a DSL for testing the mpu. It provides rackunit and utility for testing registers and flags
cleanest tests I’ve ever written I think x)
Tests are very important in emulators - it just takes too long to hunt down bugs.
How does making an emulator work in racket?
@kennethdevel pretty much the same as making an emulator in any language, except you have macros to help you :slightly_smiling_face:
but an emulator is really simple to write once you get the basics
I am a total newbie, care to explain?
you have a big list of operations you take from the datasheet of the processor you want to emulate, then you make a loop that reads a ROM file, and for each byte, executes the corresponding operation
For a simple computer you have a memory and a cpu.
A simple model for memory is just a vector of bytes.
The cpu has a program counter (pc).
The cpu loops:
- Read the instruction in memory address given by pc.
- Figure out what the instruction does (decode)
- Execute the instructions.
- Maybe increment pc
So you program is mostly one big loop.
and you can do all that in racket, or do you need to go from racket->asm at some point?
you don’t
but reading and writing asm can be useful when working with custom programs to test your emulator
if you just use ROM from real devices (like game cartridges for example), you never have to use asm
but if you want to write your own programs, you need to write assembly code and assemble it into binary
this was my case, so I made a racket assembler: https://github.com/euhmeuh/virtual-mpu/tree/master/private/asm-lang
so if you just download a ROM file you can do everything in racket?
You can think of a ROM as a snapshot of memory.
It just determines what’s in memory when your emulator is started.
my idea is also to have the CPU emulation be defined by a DSL, it’s not 100% there yet
but the DSL is also intended to be easily translated to C and assembly
one thing I want to do is create “baremetal” emulators on the raspberry pi, a dedicated emulation machine
so there will be a compiler
Will it be easy to use your emulators for training machine learning algorithms in Racket?
it’s possible, but for example my Z80 emulator runs at 2x the normal machine speed, so training can take more time than an emulator that is able to speed up more
I see
translating the emulator to C and using that would make sense
@jerome.martin.dev about your fear of frying the chip… a 6802 seems simple enough that recreating one using FPGA shouldn’t be too hard…
another project I have in mind is a Racket DSL for hardware… verilog is lame
+1
@andreiformiga have you seen Robby Findler’s mini-hdl: https://youtu.be/hFlIl0Zo234?t=35m26s
@githree I have not, thanks for the pointer
there’s also hardcaml for inspiration https://www.janestreet.com/tech-talks/ocaml-all-the-way-down/
@soegaard2 I have a PR to your 6502 readme, change “The 6502 was the star of the 8-bit era” to “The 6502 was one of the stars of the 8-bit era” :slightly_smiling_face:
well…
old school tech holy wars: 6502 vs Z80
My first computer was an zx81 - it had an z80.
here in brazil, the most popular 8-bit computer was the MSX line, most popular 8-bit console was the Sega Master System, so here the Z80 dominated
How about the drean?
the C64 was almost unknown down here
Surprised to hear that.
(From Denmark btw)
there were clones of the Apple II, ZX81 and ZX Spectrum
It is kind of strange how different 8-bit systems were popular in different countries.
I know the msx was popular in the netherlands.
yes, also spain
On the other hand the apple ii never made to denmark.
the companies that handled the MSX and the Master System here (both officially licensed) did good jobs on production, support & marketing, so they became dominant
though there were plenty of NES clones too…
I can’t remember the master system. All my friends had c64s. I think one kid had a NES.
I remember seeing Amigas here, I was pretty impressed with one I saw in a friend’s house
I don’t remember ever hearing about the C64 before the internet
@soegaard2 anyway I may base my 6502 core on your code, though I will probably change it to use my DSL
Feel free to do that.
I went zx81 -> c64 -> Amiga 500.
I am curious about emulating the C64 to try its games
After the Amiga I couldn’t grasp why anyone would buy a pc :slightly_smiling_face:
the amiga was amazing… old PCs were so bad for games
unfortunately it was too expensive here, after my MSX broke I had to wait a couple of years to be able to buy a PC, never had an amiga
I used my Amiga through high school. The word processor didn’t support math, so I had to write formulas with integral signs etc, print the document and them add the missings signs using a pen.
@greg In the screenshot you posted a few days ago, is that Emacs? Is it fairly easy to add a REPL along with the logger you have broken out?
@mwb Yes it is Emacs. The *Racket Logger*
buffer is from racket-mode
which you can package-install
from MELPA (or see source https://github.com/greghendershott/racket-mode )
@greg Thanks! I have a lot to learn about Emacs as I’ve primarily used vim but I remote a lot and would love to be able to use something in the terminal.
DrRacket is really nice, also. That is probably the best/fullest experience, especially when first learning Racket. But some folks like Emacs or Vim to explore many languages, or want to edit many other file formats, etc.